From e50e325be3eeaae082f170388abf69f40f94af36 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 24 Jul 2024 00:52:22 +0000 Subject: [PATCH] Added chart versions: codefresh/cf-runtime: - 6.3.52 digitalis/vals-operator: - 0.7.10 kuma/kuma: - 2.8.2 minio/minio-operator: - 6.0.1 new-relic/nri-bundle: - 5.0.87 percona/psmdb-db: - 1.16.3 percona/psmdb-operator: - 1.16.3 speedscale/speedscale-operator: - 2.2.203 --- assets/codefresh/cf-runtime-6.3.52.tgz | Bin 0 -> 43593 bytes assets/digitalis/vals-operator-0.7.10.tgz | Bin 0 -> 6922 bytes assets/kuma/kuma-2.8.2.tgz | Bin 0 -> 69514 bytes assets/minio/minio-operator-6.0.1.tgz | Bin 0 -> 24539 bytes assets/new-relic/nri-bundle-5.0.87.tgz | Bin 0 -> 340784 bytes assets/percona/psmdb-db-1.16.3.tgz | Bin 0 -> 13279 bytes assets/percona/psmdb-operator-1.16.3.tgz | Bin 0 -> 50494 bytes .../speedscale-operator-2.2.203.tgz | Bin 0 -> 16667 bytes .../codefresh/cf-runtime/6.3.52/.helmignore | 3 + charts/codefresh/cf-runtime/6.3.52/Chart.yaml | 28 + charts/codefresh/cf-runtime/6.3.52/README.md | 1228 + .../cf-runtime/6.3.52/README.md.gotmpl | 1007 + .../6.3.52/files/cleanup-runtime.sh | 37 + .../6.3.52/files/configure-dind-certs.sh | 132 + .../cf-runtime/6.3.52/files/init-runtime.sh | 80 + .../6.3.52/files/reconcile-runtime.sh | 38 + .../_components/app-proxy/_deployment.yaml | 70 + .../_components/app-proxy/_env-vars.yaml | 19 + .../_components/app-proxy/_helpers.tpl | 43 + .../_components/app-proxy/_ingress.yaml | 32 + .../_components/app-proxy/_rbac.yaml | 47 + .../_components/app-proxy/_service.yaml | 17 + .../event-exporter/_deployment.yaml | 62 + .../_components/event-exporter/_env-vars.yaml | 14 + .../_components/event-exporter/_helpers.tpl | 43 + .../_components/event-exporter/_rbac.yaml | 47 + .../_components/event-exporter/_service.yaml | 17 + .../event-exporter/_serviceMontor.yaml | 14 + .../_components/monitor/_deployment.yaml | 70 + .../_components/monitor/_env-vars.yaml | 26 + .../_components/monitor/_helpers.tpl | 42 + .../templates/_components/monitor/_rbac.yaml | 56 + .../_components/monitor/_service.yaml | 17 + .../_components/runner/_deployment.yaml | 103 + .../templates/_components/runner/_helpers.tpl | 42 + .../templates/_components/runner/_rbac.yaml | 53 + .../_init-container.yaml | 30 + .../_main-container.yaml | 28 + .../_sidecar-container.yaml | 22 + .../volume-provisioner/_cronjob.yaml | 58 + .../volume-provisioner/_daemonset.yaml | 98 + .../volume-provisioner/_deployment.yaml | 67 + .../volume-provisioner/_env-vars.yaml | 88 + .../volume-provisioner/_helpers.tpl | 93 + .../_components/volume-provisioner/_rbac.yaml | 71 + .../volume-provisioner/_secret.yaml | 22 + .../volume-provisioner/_storageclass.yaml | 47 + .../cf-runtime/6.3.52/templates/_helpers.tpl | 51 + .../templates/app-proxy/deployment.yaml | 9 + .../6.3.52/templates/app-proxy/ingress.yaml | 9 + .../6.3.52/templates/app-proxy/rbac.yaml | 9 + .../6.3.52/templates/app-proxy/service.yaml | 9 + .../templates/event-exporter/deployment.yaml | 9 + .../6.3.52/templates/event-exporter/rbac.yaml | 9 + .../templates/event-exporter/service.yaml | 11 + .../templates/extra/extra-resources.yaml | 6 + .../templates/extra/runtime-images-cm.yaml | 19 + .../hooks/post-install/cm-update-runtime.yaml | 18 + .../hooks/post-install/job-gencerts-dind.yaml | 68 + .../post-install/job-update-runtime.yaml | 77 + .../post-install/rbac-gencerts-dind.yaml | 37 + .../pre-delete/job-cleanup-resources.yaml | 73 + .../pre-delete/rbac-cleanup-resources.yaml | 46 + .../6.3.52/templates/monitor/deployment.yaml | 9 + .../6.3.52/templates/monitor/rbac.yaml | 9 + .../6.3.52/templates/monitor/service.yaml | 9 + .../templates/other/external-secrets.yaml | 2 + .../6.3.52/templates/other/podMonitor.yaml | 2 + .../templates/other/serviceMonitor.yaml | 2 + .../6.3.52/templates/runner/deployment.yaml | 9 + .../6.3.52/templates/runner/rbac.yaml | 9 + .../6.3.52/templates/runtime/_helpers.tpl | 123 + .../templates/runtime/cm-dind-daemon.yaml | 10 + .../6.3.52/templates/runtime/rbac.yaml | 48 + .../runtime/runtime-env-spec-tmpl.yaml | 210 + .../6.3.52/templates/runtime/secret.yaml | 11 + .../6.3.52/templates/runtime/svc-dind.yaml | 16 + .../templates/volume-provisioner/cronjob.yaml | 11 + .../volume-provisioner/daemonset.yaml | 11 + .../volume-provisioner/deployment.yaml | 10 + .../templates/volume-provisioner/rbac.yaml | 9 + .../templates/volume-provisioner/secret.yaml | 10 + .../volume-provisioner/storageclass.yaml | 10 + .../codefresh/cf-runtime/6.3.52/values.yaml | 946 + .../digitalis/vals-operator/0.7.10/.gitignore | 49 + .../digitalis/vals-operator/0.7.10/Chart.yaml | 23 + .../digitalis/vals-operator/0.7.10/README.md | 55 + .../vals-operator/0.7.10/app-readme.md | 9 + .../vals-operator/0.7.10/crds/dbsecrets.yaml | 85 + .../0.7.10/crds/valssecrets.yaml | 134 + .../vals-operator/0.7.10/questions.yaml | 26 + .../vals-operator/0.7.10/templates/NOTES.txt | 0 .../0.7.10/templates/_helpers.tpl | 62 + .../vals-operator/0.7.10/templates/crds.yaml | 7 + .../0.7.10/templates/deployment.yaml | 75 + .../0.7.10/templates/podmonitor.yaml | 20 + .../0.7.10/templates/prometheusrules.yaml | 68 + .../0.7.10/templates/serviceaccount.yaml | 91 + .../vals-operator/0.7.10/values.yaml | 117 + charts/kuma/kuma/2.8.2/.helmdocsignore | 1 + charts/kuma/kuma/2.8.2/.helmignore | 23 + charts/kuma/kuma/2.8.2/Chart.yaml | 26 + charts/kuma/kuma/2.8.2/README.md | 256 + charts/kuma/kuma/2.8.2/README.md.gotmpl | 52 + .../2.8.2/crds/kuma.io_circuitbreakers.yaml | 50 + .../2.8.2/crds/kuma.io_containerpatches.yaml | 114 + .../2.8.2/crds/kuma.io_dataplaneinsights.yaml | 50 + .../kuma/2.8.2/crds/kuma.io_dataplanes.yaml | 70 + .../2.8.2/crds/kuma.io_externalservices.yaml | 50 + .../2.8.2/crds/kuma.io_faultinjections.yaml | 50 + .../kuma/2.8.2/crds/kuma.io_healthchecks.yaml | 50 + .../crds/kuma.io_hostnamegenerators.yaml | 65 + .../2.8.2/crds/kuma.io_meshaccesslogs.yaml | 556 + .../crds/kuma.io_meshcircuitbreakers.yaml | 738 + .../kuma/kuma/2.8.2/crds/kuma.io_meshes.yaml | 50 + .../crds/kuma.io_meshexternalservices.yaml | 333 + .../crds/kuma.io_meshfaultinjections.yaml | 419 + .../crds/kuma.io_meshgatewayinstances.yaml | 364 + .../2.8.2/crds/kuma.io_meshgatewayroutes.yaml | 50 + .../kuma/2.8.2/crds/kuma.io_meshgateways.yaml | 50 + .../2.8.2/crds/kuma.io_meshhealthchecks.yaml | 382 + .../2.8.2/crds/kuma.io_meshhttproutes.yaml | 664 + .../kuma/2.8.2/crds/kuma.io_meshinsights.yaml | 50 + .../kuma.io_meshloadbalancingstrategies.yaml | 572 + .../kuma/2.8.2/crds/kuma.io_meshmetrics.yaml | 293 + .../2.8.2/crds/kuma.io_meshpassthroughs.yaml | 167 + .../2.8.2/crds/kuma.io_meshproxypatches.yaml | 560 + .../2.8.2/crds/kuma.io_meshratelimits.yaml | 498 + .../kuma/2.8.2/crds/kuma.io_meshretries.yaml | 507 + .../kuma/2.8.2/crds/kuma.io_meshservices.yaml | 195 + .../2.8.2/crds/kuma.io_meshtcproutes.yaml | 281 + .../kuma/2.8.2/crds/kuma.io_meshtimeouts.yaml | 362 + .../kuma/2.8.2/crds/kuma.io_meshtraces.yaml | 284 + .../crds/kuma.io_meshtrafficpermissions.yaml | 203 + .../2.8.2/crds/kuma.io_proxytemplates.yaml | 50 + .../kuma/2.8.2/crds/kuma.io_ratelimits.yaml | 50 + .../kuma/kuma/2.8.2/crds/kuma.io_retries.yaml | 50 + .../2.8.2/crds/kuma.io_serviceinsights.yaml | 50 + .../kuma/2.8.2/crds/kuma.io_timeouts.yaml | 50 + .../kuma/2.8.2/crds/kuma.io_trafficlogs.yaml | 50 + .../crds/kuma.io_trafficpermissions.yaml | 50 + .../2.8.2/crds/kuma.io_trafficroutes.yaml | 50 + .../2.8.2/crds/kuma.io_traffictraces.yaml | 50 + .../2.8.2/crds/kuma.io_virtualoutbounds.yaml | 50 + .../kuma/2.8.2/crds/kuma.io_zoneegresses.yaml | 56 + .../crds/kuma.io_zoneegressinsights.yaml | 50 + .../2.8.2/crds/kuma.io_zoneingresses.yaml | 56 + .../crds/kuma.io_zoneingressinsights.yaml | 51 + .../kuma/2.8.2/crds/kuma.io_zoneinsights.yaml | 50 + .../kuma/kuma/2.8.2/crds/kuma.io_zones.yaml | 50 + charts/kuma/kuma/2.8.2/templates/NOTES.txt | 42 + charts/kuma/kuma/2.8.2/templates/_helpers.tpl | 402 + .../kuma/2.8.2/templates/cni-configmap.yaml | 22 + .../kuma/2.8.2/templates/cni-daemonset.yaml | 152 + .../kuma/kuma/2.8.2/templates/cni-rbac.yaml | 51 + .../kuma/2.8.2/templates/cp-configmap.yaml | 33 + .../kuma/2.8.2/templates/cp-deployment.yaml | 398 + .../templates/cp-global-sync-service.yaml | 33 + charts/kuma/kuma/2.8.2/templates/cp-hpa.yaml | 24 + .../kuma/kuma/2.8.2/templates/cp-ingress.yaml | 25 + .../cp-kds-global-server-secret.yaml | 15 + .../cp-kds-zone-client-tls-secret.yaml | 13 + charts/kuma/kuma/2.8.2/templates/cp-pdb.yaml | 20 + charts/kuma/kuma/2.8.2/templates/cp-rbac.yaml | 315 + .../kuma/kuma/2.8.2/templates/cp-service.yaml | 49 + .../templates/cp-webhooks-and-secrets.yaml | 337 + .../2.8.2/templates/egress-deployment.yaml | 137 + .../kuma/kuma/2.8.2/templates/egress-hpa.yaml | 24 + .../kuma/kuma/2.8.2/templates/egress-pdb.yaml | 20 + .../kuma/2.8.2/templates/egress-rbac.yaml | 18 + .../kuma/2.8.2/templates/egress-service.yaml | 32 + .../kuma/2.8.2/templates/gateway-class.yaml | 19 + .../2.8.2/templates/ingress-deployment.yaml | 141 + .../kuma/2.8.2/templates/ingress-hpa.yaml | 24 + .../kuma/2.8.2/templates/ingress-pdb.yaml | 20 + .../kuma/2.8.2/templates/ingress-rbac.yaml | 18 + .../kuma/2.8.2/templates/ingress-service.yaml | 32 + .../post-delete-cleanup-ebpf-job.yaml | 126 + .../2.8.2/templates/pre-delete-webhooks.yaml | 109 + .../pre-install-patch-namespace-job.yaml | 124 + .../pre-upgrade-install-crds-job.yaml | 171 + charts/kuma/kuma/2.8.2/values.yaml | 748 + charts/minio/minio-operator/6.0.1/.helmignore | 22 + charts/minio/minio-operator/6.0.1/Chart.yaml | 23 + charts/minio/minio-operator/6.0.1/README.md | 45 + .../minio/minio-operator/6.0.1/app-readme.md | 78 + .../6.0.1/templates/_helpers.tpl | 59 + .../6.0.1/templates/job.min.io_jobs.yaml | 1201 + .../6.0.1/templates/minio.min.io_tenants.yaml | 5670 +++++ .../6.0.1/templates/operator-clusterrole.yaml | 180 + .../operator-clusterrolebinding.yaml | 13 + .../6.0.1/templates/operator-deployment.yaml | 67 + .../6.0.1/templates/operator-service.yaml | 14 + .../templates/operator-serviceaccount.yaml | 10 + .../6.0.1/templates/sts-service.yaml | 12 + .../templates/sts.min.io_policybindings.yaml | 133 + charts/minio/minio-operator/6.0.1/values.yaml | 191 + .../new-relic/nri-bundle/5.0.87/.helmignore | 22 + charts/new-relic/nri-bundle/5.0.87/Chart.lock | 39 + charts/new-relic/nri-bundle/5.0.87/Chart.yaml | 85 + charts/new-relic/nri-bundle/5.0.87/README.md | 200 + .../nri-bundle/5.0.87/README.md.gotmpl | 166 + .../new-relic/nri-bundle/5.0.87/app-readme.md | 5 + .../charts/k8s-agents-operator/.helmignore | 23 + .../charts/k8s-agents-operator/Chart.yaml | 16 + .../charts/k8s-agents-operator/README.md | 191 + .../k8s-agents-operator/README.md.gotmpl | 157 + .../k8s-agents-operator/templates/NOTES.txt | 36 + .../templates/_helpers.tpl | 80 + .../templates/certmanager.yaml | 17 + .../templates/deployment.yaml | 91 + .../templates/instrumentation-crd.yaml | 1150 + .../templates/leader-election-rbac.yaml | 49 + .../templates/manager-rbac.yaml | 76 + .../mutating-webhook-configuration.yaml | 49 + .../templates/newrelic_license_secret.yaml | 14 + .../templates/proxy-rbac.yaml | 34 + .../templates/reader-rbac.yaml | 11 + .../templates/selfsigned-issuer.yaml | 8 + .../templates/service.yaml | 15 + .../validating-webhook-configuration.yaml | 48 + .../templates/webhook-service.yaml | 15 + .../charts/k8s-agents-operator/values.yaml | 62 + .../charts/kube-state-metrics/.helmignore | 21 + .../charts/kube-state-metrics/Chart.yaml | 26 + .../charts/kube-state-metrics/README.md | 85 + .../kube-state-metrics/templates/NOTES.txt | 23 + .../kube-state-metrics/templates/_helpers.tpl | 156 + .../templates/ciliumnetworkpolicy.yaml | 33 + .../templates/clusterrolebinding.yaml | 20 + .../templates/crs-configmap.yaml | 16 + .../templates/deployment.yaml | 279 + .../templates/extra-manifests.yaml | 4 + .../templates/kubeconfig-secret.yaml | 12 + .../templates/networkpolicy.yaml | 43 + .../kube-state-metrics/templates/pdb.yaml | 18 + .../templates/podsecuritypolicy.yaml | 39 + .../templates/psp-clusterrole.yaml | 19 + .../templates/psp-clusterrolebinding.yaml | 16 + .../templates/rbac-configmap.yaml | 22 + .../kube-state-metrics/templates/role.yaml | 212 + .../templates/rolebinding.yaml | 24 + .../kube-state-metrics/templates/service.yaml | 49 + .../templates/serviceaccount.yaml | 15 + .../templates/servicemonitor.yaml | 114 + .../templates/stsdiscovery-role.yaml | 26 + .../templates/stsdiscovery-rolebinding.yaml | 17 + .../templates/verticalpodautoscaler.yaml | 44 + .../charts/kube-state-metrics/values.yaml | 441 + .../newrelic-infra-operator/.helmignore | 1 + .../charts/newrelic-infra-operator/Chart.lock | 6 + .../charts/newrelic-infra-operator/Chart.yaml | 35 + .../charts/newrelic-infra-operator/README.md | 114 + .../newrelic-infra-operator/README.md.gotmpl | 77 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 17 + .../charts/common-library/DEVELOPERS.md | 663 + .../charts/common-library/README.md | 106 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 26 + .../common-library/templates/_cluster.tpl | 15 + .../templates/_custom-attributes.tpl | 17 + .../common-library/templates/_dnsconfig.tpl | 10 + .../common-library/templates/_fedramp.tpl | 25 + .../common-library/templates/_hostnetwork.tpl | 39 + .../common-library/templates/_images.tpl | 94 + .../common-library/templates/_insights.tpl | 56 + .../templates/_insights_secret.yaml.tpl | 21 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 56 + .../templates/_license_secret.yaml.tpl | 21 + .../templates/_low-data-mode.tpl | 26 + .../common-library/templates/_naming.tpl | 73 + .../templates/_nodeselector.tpl | 10 + .../templates/_priority-class-name.tpl | 10 + .../common-library/templates/_privileged.tpl | 28 + .../common-library/templates/_proxy.tpl | 10 + .../templates/_security-context.tpl | 23 + .../templates/_serviceaccount.tpl | 90 + .../common-library/templates/_staging.tpl | 39 + .../common-library/templates/_tolerations.tpl | 10 + .../common-library/templates/_verbose-log.tpl | 54 + .../charts/common-library/values.yaml | 1 + .../ci/test-values.yaml | 39 + .../templates/NOTES.txt | 4 + .../templates/_helpers.tpl | 136 + .../job-patch/clusterrole.yaml | 27 + .../job-patch/clusterrolebinding.yaml | 20 + .../job-patch/job-createSecret.yaml | 57 + .../job-patch/job-patchWebhook.yaml | 57 + .../admission-webhooks/job-patch/psp.yaml | 50 + .../admission-webhooks/job-patch/role.yaml | 21 + .../job-patch/rolebinding.yaml | 21 + .../job-patch/serviceaccount.yaml | 14 + .../mutatingWebhookConfiguration.yaml | 32 + .../templates/cert-manager.yaml | 52 + .../templates/clusterrole.yaml | 39 + .../templates/clusterrolebinding.yaml | 26 + .../templates/configmap.yaml | 9 + .../templates/deployment.yaml | 92 + .../templates/secret.yaml | 2 + .../templates/service.yaml | 13 + .../templates/serviceaccount.yaml | 13 + .../tests/deployment_test.yaml | 32 + .../tests/job_patch_psp_test.yaml | 23 + .../tests/job_serviceaccount_test.yaml | 64 + .../tests/rbac_test.yaml | 41 + .../newrelic-infra-operator/values.yaml | 222 + .../newrelic-infrastructure/.helmignore | 1 + .../charts/newrelic-infrastructure/Chart.lock | 6 + .../charts/newrelic-infrastructure/Chart.yaml | 26 + .../charts/newrelic-infrastructure/README.md | 220 + .../newrelic-infrastructure/README.md.gotmpl | 137 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 17 + .../charts/common-library/DEVELOPERS.md | 663 + .../charts/common-library/README.md | 106 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 26 + .../common-library/templates/_cluster.tpl | 15 + .../templates/_custom-attributes.tpl | 17 + .../common-library/templates/_dnsconfig.tpl | 10 + .../common-library/templates/_fedramp.tpl | 25 + .../common-library/templates/_hostnetwork.tpl | 39 + .../common-library/templates/_images.tpl | 94 + .../common-library/templates/_insights.tpl | 56 + .../templates/_insights_secret.yaml.tpl | 21 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 56 + .../templates/_license_secret.yaml.tpl | 21 + .../templates/_low-data-mode.tpl | 26 + .../common-library/templates/_naming.tpl | 73 + .../templates/_nodeselector.tpl | 10 + .../templates/_priority-class-name.tpl | 10 + .../common-library/templates/_privileged.tpl | 28 + .../common-library/templates/_proxy.tpl | 10 + .../templates/_security-context.tpl | 23 + .../templates/_serviceaccount.tpl | 90 + .../common-library/templates/_staging.tpl | 39 + .../common-library/templates/_tolerations.tpl | 10 + .../common-library/templates/_verbose-log.tpl | 54 + .../charts/common-library/values.yaml | 1 + .../test-cplane-kind-deployment-values.yaml | 135 + .../ci/test-values.yaml | 134 + .../templates/NOTES.txt | 131 + .../templates/_helpers.tpl | 118 + .../templates/_helpers_compatibility.tpl | 202 + .../templates/clusterrole.yaml | 35 + .../templates/clusterrolebinding.yaml | 16 + .../controlplane/_affinity_helper.tpl | 11 + .../controlplane/_agent-config_helper.tpl | 20 + .../templates/controlplane/_host_network.tpl | 22 + .../templates/controlplane/_naming.tpl | 16 + .../templates/controlplane/_rbac.tpl | 40 + .../controlplane/_tolerations_helper.tpl | 11 + .../controlplane/agent-configmap.yaml | 18 + .../templates/controlplane/clusterrole.yaml | 47 + .../controlplane/clusterrolebinding.yaml | 16 + .../templates/controlplane/daemonset.yaml | 205 + .../templates/controlplane/rolebinding.yaml | 21 + .../controlplane/scraper-configmap.yaml | 36 + .../controlplane/serviceaccount.yaml | 13 + .../templates/ksm/_affinity_helper.tpl | 14 + .../templates/ksm/_agent-config_helper.tpl | 20 + .../templates/ksm/_host_network.tpl | 22 + .../templates/ksm/_naming.tpl | 8 + .../templates/ksm/_tolerations_helper.tpl | 11 + .../templates/ksm/agent-configmap.yaml | 18 + .../templates/ksm/deployment.yaml | 192 + .../templates/ksm/scraper-configmap.yaml | 15 + .../templates/kubelet/_affinity_helper.tpl | 33 + .../kubelet/_agent-config_helper.tpl | 31 + .../templates/kubelet/_host_network.tpl | 22 + .../templates/kubelet/_naming.tpl | 12 + .../kubelet/_security_context_helper.tpl | 32 + .../templates/kubelet/_tolerations_helper.tpl | 11 + .../templates/kubelet/agent-configmap.yaml | 18 + .../templates/kubelet/daemonset.yaml | 265 + .../kubelet/integrations-configmap.yaml | 72 + .../templates/kubelet/scraper-configmap.yaml | 18 + .../templates/podsecuritypolicy.yaml | 26 + .../templates/secret.yaml | 2 + .../templates/serviceaccount.yaml | 13 + .../newrelic-infrastructure/values.yaml | 602 + .../newrelic-k8s-metrics-adapter/.helmignore | 25 + .../newrelic-k8s-metrics-adapter/Chart.lock | 6 + .../newrelic-k8s-metrics-adapter/Chart.yaml | 25 + .../newrelic-k8s-metrics-adapter/README.md | 139 + .../README.md.gotmpl | 107 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 17 + .../charts/common-library/DEVELOPERS.md | 663 + .../charts/common-library/README.md | 106 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 26 + .../common-library/templates/_cluster.tpl | 15 + .../templates/_custom-attributes.tpl | 17 + .../common-library/templates/_dnsconfig.tpl | 10 + .../common-library/templates/_fedramp.tpl | 25 + .../common-library/templates/_hostnetwork.tpl | 39 + .../common-library/templates/_images.tpl | 94 + .../common-library/templates/_insights.tpl | 56 + .../templates/_insights_secret.yaml.tpl | 21 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 56 + .../templates/_license_secret.yaml.tpl | 21 + .../templates/_low-data-mode.tpl | 26 + .../common-library/templates/_naming.tpl | 73 + .../templates/_nodeselector.tpl | 10 + .../templates/_priority-class-name.tpl | 10 + .../common-library/templates/_privileged.tpl | 28 + .../common-library/templates/_proxy.tpl | 10 + .../templates/_security-context.tpl | 23 + .../templates/_serviceaccount.tpl | 90 + .../common-library/templates/_staging.tpl | 39 + .../common-library/templates/_tolerations.tpl | 10 + .../common-library/templates/_verbose-log.tpl | 54 + .../charts/common-library/values.yaml | 1 + .../ci/test-values.yaml | 14 + .../templates/_helpers.tpl | 57 + .../templates/adapter-clusterrolebinding.yaml | 14 + .../templates/adapter-rolebinding.yaml | 15 + .../templates/apiservice/apiservice.yaml | 19 + .../apiservice/job-patch/clusterrole.yaml | 26 + .../job-patch/clusterrolebinding.yaml | 19 + .../job-patch/job-createSecret.yaml | 55 + .../job-patch/job-patchAPIService.yaml | 53 + .../templates/apiservice/job-patch/psp.yaml | 49 + .../templates/apiservice/job-patch/role.yaml | 20 + .../apiservice/job-patch/rolebinding.yaml | 20 + .../apiservice/job-patch/serviceaccount.yaml | 18 + .../templates/configmap.yaml | 19 + .../templates/deployment.yaml | 113 + .../templates/hpa-clusterrole.yaml | 15 + .../templates/hpa-clusterrolebinding.yaml | 14 + .../templates/secret.yaml | 10 + .../templates/service.yaml | 13 + .../templates/serviceaccount.yaml | 13 + .../tests/apiservice_test.yaml | 22 + .../tests/common_extra_naming_test.yaml | 27 + .../tests/configmap_test.yaml | 104 + .../tests/deployment_test.yaml | 99 + .../tests/hpa_clusterrolebinding_test.yaml | 18 + .../job_patch_cluster_rolebinding_test.yaml | 22 + .../tests/job_patch_clusterrole_test.yaml | 20 + .../tests/job_patch_common_test.yaml | 27 + .../job_patch_job_createsecret_test.yaml | 47 + .../job_patch_job_patchapiservice_test.yaml | 56 + .../tests/job_serviceaccount_test.yaml | 79 + .../tests/rbac_test.yaml | 50 + .../newrelic-k8s-metrics-adapter/values.yaml | 156 + .../5.0.87/charts/newrelic-logging/Chart.lock | 6 + .../5.0.87/charts/newrelic-logging/Chart.yaml | 20 + .../5.0.87/charts/newrelic-logging/README.md | 267 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 17 + .../charts/common-library/DEVELOPERS.md | 663 + .../charts/common-library/README.md | 106 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 26 + .../common-library/templates/_cluster.tpl | 15 + .../templates/_custom-attributes.tpl | 17 + .../common-library/templates/_dnsconfig.tpl | 10 + .../common-library/templates/_fedramp.tpl | 25 + .../common-library/templates/_hostnetwork.tpl | 39 + .../common-library/templates/_images.tpl | 94 + .../common-library/templates/_insights.tpl | 56 + .../templates/_insights_secret.yaml.tpl | 21 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 56 + .../templates/_license_secret.yaml.tpl | 21 + .../templates/_low-data-mode.tpl | 26 + .../common-library/templates/_naming.tpl | 73 + .../templates/_nodeselector.tpl | 10 + .../templates/_priority-class-name.tpl | 10 + .../common-library/templates/_privileged.tpl | 28 + .../common-library/templates/_proxy.tpl | 10 + .../templates/_security-context.tpl | 23 + .../templates/_serviceaccount.tpl | 90 + .../common-library/templates/_staging.tpl | 39 + .../common-library/templates/_tolerations.tpl | 10 + .../common-library/templates/_verbose-log.tpl | 54 + .../charts/common-library/values.yaml | 1 + .../ci/test-enable-windows-values.yaml | 2 + .../ci/test-lowdatamode-values.yaml | 1 + .../ci/test-override-global-lowdatamode.yaml | 3 + .../ci/test-staging-values.yaml | 1 + .../ci/test-with-empty-global.yaml | 1 + .../ci/test-with-empty-values.yaml | 0 ...and-plugin-metrics-dashboard-template.json | 2237 ++ .../newrelic-logging/templates/NOTES.txt | 18 + .../newrelic-logging/templates/_helpers.tpl | 215 + .../templates/clusterrole.yaml | 23 + .../templates/clusterrolebinding.yaml | 15 + .../newrelic-logging/templates/configmap.yaml | 38 + .../templates/daemonset-windows.yaml | 171 + .../newrelic-logging/templates/daemonset.yaml | 208 + .../templates/persistentvolume.yaml | 57 + .../templates/podsecuritypolicy.yaml | 24 + .../newrelic-logging/templates/secret.yaml | 12 + .../templates/serviceaccount.yaml | 17 + .../tests/cri_parser_test.yaml | 37 + .../tests/dns_config_test.yaml | 62 + .../tests/endpoint_region_selection_test.yaml | 128 + .../fluentbit_k8logging_exclude_test.yaml | 45 + .../tests/fluentbit_persistence_test.yaml | 317 + .../tests/fluentbit_pod_label_test.yaml | 48 + .../tests/fluentbit_sendmetrics_test.yaml | 74 + .../newrelic-logging/tests/images_test.yaml | 96 + .../tests/linux_volume_mount_test.yaml | 37 + .../newrelic-logging/tests/rbac_test.yaml | 48 + .../charts/newrelic-logging/values.yaml | 357 + .../5.0.87/charts/newrelic-pixie/Chart.yaml | 18 + .../5.0.87/charts/newrelic-pixie/README.md | 166 + .../charts/newrelic-pixie/ci/test-values.yaml | 5 + .../charts/newrelic-pixie/templates/NOTES.txt | 27 + .../newrelic-pixie/templates/_helpers.tpl | 172 + .../newrelic-pixie/templates/configmap.yaml | 12 + .../charts/newrelic-pixie/templates/job.yaml | 164 + .../newrelic-pixie/templates/secret.yaml | 20 + .../newrelic-pixie/tests/configmap.yaml | 44 + .../charts/newrelic-pixie/tests/jobs.yaml | 138 + .../5.0.87/charts/newrelic-pixie/values.yaml | 70 + .../newrelic-prometheus-agent/.helmignore | 23 + .../newrelic-prometheus-agent/Chart.lock | 6 + .../newrelic-prometheus-agent/Chart.yaml | 22 + .../newrelic-prometheus-agent/README.md | 244 + .../README.md.gotmpl | 209 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 17 + .../charts/common-library/DEVELOPERS.md | 663 + .../charts/common-library/README.md | 106 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 26 + .../common-library/templates/_cluster.tpl | 15 + .../templates/_custom-attributes.tpl | 17 + .../common-library/templates/_dnsconfig.tpl | 10 + .../common-library/templates/_fedramp.tpl | 25 + .../common-library/templates/_hostnetwork.tpl | 39 + .../common-library/templates/_images.tpl | 94 + .../common-library/templates/_insights.tpl | 56 + .../templates/_insights_secret.yaml.tpl | 21 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 56 + .../templates/_license_secret.yaml.tpl | 21 + .../templates/_low-data-mode.tpl | 26 + .../common-library/templates/_naming.tpl | 73 + .../templates/_nodeselector.tpl | 10 + .../templates/_priority-class-name.tpl | 10 + .../common-library/templates/_privileged.tpl | 28 + .../common-library/templates/_proxy.tpl | 10 + .../templates/_security-context.tpl | 23 + .../templates/_serviceaccount.tpl | 90 + .../common-library/templates/_staging.tpl | 39 + .../common-library/templates/_tolerations.tpl | 10 + .../common-library/templates/_verbose-log.tpl | 54 + .../charts/common-library/values.yaml | 1 + .../ci/test-values.yaml | 6 + .../static/lowdatamodedefaults.yaml | 6 + .../static/metrictyperelabeldefaults.yaml | 17 + .../templates/_helpers.tpl | 165 + .../templates/clusterrole.yaml | 24 + .../templates/clusterrolebinding.yaml | 16 + .../templates/configmap.yaml | 31 + .../templates/secret.yaml | 2 + .../templates/serviceaccount.yaml | 13 + .../templates/statefulset.yaml | 157 + .../tests/configmap_test.yaml | 572 + .../tests/configurator_image_test.yaml | 57 + .../tests/integration_filters_test.yaml | 119 + .../tests/lowdatamode_configmap_test.yaml | 138 + .../newrelic-prometheus-agent/values.yaml | 473 + .../5.0.87/charts/nri-kube-events/Chart.lock | 6 + .../5.0.87/charts/nri-kube-events/Chart.yaml | 26 + .../5.0.87/charts/nri-kube-events/README.md | 79 + .../charts/nri-kube-events/README.md.gotmpl | 43 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 17 + .../charts/common-library/DEVELOPERS.md | 663 + .../charts/common-library/README.md | 106 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 26 + .../common-library/templates/_cluster.tpl | 15 + .../templates/_custom-attributes.tpl | 17 + .../common-library/templates/_dnsconfig.tpl | 10 + .../common-library/templates/_fedramp.tpl | 25 + .../common-library/templates/_hostnetwork.tpl | 39 + .../common-library/templates/_images.tpl | 94 + .../common-library/templates/_insights.tpl | 56 + .../templates/_insights_secret.yaml.tpl | 21 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 56 + .../templates/_license_secret.yaml.tpl | 21 + .../templates/_low-data-mode.tpl | 26 + .../common-library/templates/_naming.tpl | 73 + .../templates/_nodeselector.tpl | 10 + .../templates/_priority-class-name.tpl | 10 + .../common-library/templates/_privileged.tpl | 28 + .../common-library/templates/_proxy.tpl | 10 + .../templates/_security-context.tpl | 23 + .../templates/_serviceaccount.tpl | 90 + .../common-library/templates/_staging.tpl | 39 + .../common-library/templates/_tolerations.tpl | 10 + .../common-library/templates/_verbose-log.tpl | 54 + .../charts/common-library/values.yaml | 1 + .../ci/test-bare-minimum-values.yaml | 3 + .../ci/test-custom-attributes-as-map.yaml | 12 + .../ci/test-custom-attributes-as-string.yaml | 11 + .../nri-kube-events/ci/test-values.yaml | 60 + .../nri-kube-events/templates/NOTES.txt | 3 + .../nri-kube-events/templates/_helpers.tpl | 45 + .../templates/_helpers_compatibility.tpl | 262 + .../templates/agent-configmap.yaml | 12 + .../templates/clusterrole.yaml | 42 + .../templates/clusterrolebinding.yaml | 16 + .../nri-kube-events/templates/configmap.yaml | 23 + .../nri-kube-events/templates/deployment.yaml | 124 + .../nri-kube-events/templates/secret.yaml | 2 + .../templates/serviceaccount.yaml | 11 + .../tests/agent_configmap_test.yaml | 46 + .../nri-kube-events/tests/configmap_test.yaml | 139 + .../tests/deployment_test.yaml | 104 + .../nri-kube-events/tests/images_test.yaml | 168 + .../tests/security_context_test.yaml | 77 + .../5.0.87/charts/nri-kube-events/values.yaml | 135 + .../charts/nri-metadata-injection/.helmignore | 1 + .../charts/nri-metadata-injection/Chart.lock | 6 + .../charts/nri-metadata-injection/Chart.yaml | 25 + .../charts/nri-metadata-injection/README.md | 68 + .../nri-metadata-injection/README.md.gotmpl | 41 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 17 + .../charts/common-library/DEVELOPERS.md | 663 + .../charts/common-library/README.md | 106 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 26 + .../common-library/templates/_cluster.tpl | 15 + .../templates/_custom-attributes.tpl | 17 + .../common-library/templates/_dnsconfig.tpl | 10 + .../common-library/templates/_fedramp.tpl | 25 + .../common-library/templates/_hostnetwork.tpl | 39 + .../common-library/templates/_images.tpl | 94 + .../common-library/templates/_insights.tpl | 56 + .../templates/_insights_secret.yaml.tpl | 21 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 56 + .../templates/_license_secret.yaml.tpl | 21 + .../templates/_low-data-mode.tpl | 26 + .../common-library/templates/_naming.tpl | 73 + .../templates/_nodeselector.tpl | 10 + .../templates/_priority-class-name.tpl | 10 + .../common-library/templates/_privileged.tpl | 28 + .../common-library/templates/_proxy.tpl | 10 + .../templates/_security-context.tpl | 23 + .../templates/_serviceaccount.tpl | 90 + .../common-library/templates/_staging.tpl | 39 + .../common-library/templates/_tolerations.tpl | 10 + .../common-library/templates/_verbose-log.tpl | 54 + .../charts/common-library/values.yaml | 1 + .../ci/test-values.yaml | 5 + .../templates/NOTES.txt | 23 + .../templates/_helpers.tpl | 72 + .../job-patch/clusterrole.yaml | 27 + .../job-patch/clusterrolebinding.yaml | 20 + .../job-patch/job-createSecret.yaml | 61 + .../job-patch/job-patchWebhook.yaml | 61 + .../admission-webhooks/job-patch/psp.yaml | 50 + .../admission-webhooks/job-patch/role.yaml | 21 + .../job-patch/rolebinding.yaml | 21 + .../job-patch/serviceaccount.yaml | 14 + .../mutatingWebhookConfiguration.yaml | 36 + .../templates/cert-manager.yaml | 53 + .../templates/deployment.yaml | 85 + .../templates/service.yaml | 13 + .../tests/cluster_test.yaml | 39 + .../tests/job_serviceaccount_test.yaml | 59 + .../tests/rbac_test.yaml | 38 + .../tests/volume_mounts_test.yaml | 30 + .../charts/nri-metadata-injection/values.yaml | 102 + .../5.0.87/charts/nri-prometheus/.helmignore | 22 + .../5.0.87/charts/nri-prometheus/Chart.lock | 6 + .../5.0.87/charts/nri-prometheus/Chart.yaml | 29 + .../5.0.87/charts/nri-prometheus/README.md | 116 + .../charts/nri-prometheus/README.md.gotmpl | 83 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 17 + .../charts/common-library/DEVELOPERS.md | 663 + .../charts/common-library/README.md | 106 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 26 + .../common-library/templates/_cluster.tpl | 15 + .../templates/_custom-attributes.tpl | 17 + .../common-library/templates/_dnsconfig.tpl | 10 + .../common-library/templates/_fedramp.tpl | 25 + .../common-library/templates/_hostnetwork.tpl | 39 + .../common-library/templates/_images.tpl | 94 + .../common-library/templates/_insights.tpl | 56 + .../templates/_insights_secret.yaml.tpl | 21 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 56 + .../templates/_license_secret.yaml.tpl | 21 + .../templates/_low-data-mode.tpl | 26 + .../common-library/templates/_naming.tpl | 73 + .../templates/_nodeselector.tpl | 10 + .../templates/_priority-class-name.tpl | 10 + .../common-library/templates/_privileged.tpl | 28 + .../common-library/templates/_proxy.tpl | 10 + .../templates/_security-context.tpl | 23 + .../templates/_serviceaccount.tpl | 90 + .../common-library/templates/_staging.tpl | 39 + .../common-library/templates/_tolerations.tpl | 10 + .../common-library/templates/_verbose-log.tpl | 54 + .../charts/common-library/values.yaml | 1 + .../ci/test-lowdatamode-values.yaml | 9 + .../ci/test-override-global-lowdatamode.yaml | 10 + .../charts/nri-prometheus/ci/test-values.yaml | 104 + .../static/lowdatamodedefaults.yaml | 10 + .../nri-prometheus/templates/_helpers.tpl | 15 + .../nri-prometheus/templates/clusterrole.yaml | 23 + .../templates/clusterrolebinding.yaml | 16 + .../nri-prometheus/templates/configmap.yaml | 21 + .../nri-prometheus/templates/deployment.yaml | 98 + .../nri-prometheus/templates/secret.yaml | 2 + .../templates/serviceaccount.yaml | 13 + .../nri-prometheus/tests/configmap_test.yaml | 86 + .../nri-prometheus/tests/deployment_test.yaml | 82 + .../nri-prometheus/tests/labels_test.yaml | 32 + .../5.0.87/charts/nri-prometheus/values.yaml | 251 + .../charts/pixie-operator-chart/Chart.yaml | 4 + .../pixie-operator-chart/crds/olm_crd.yaml | 9045 ++++++++ .../pixie-operator-chart/crds/vizier_crd.yaml | 347 + .../templates/00_olm.yaml | 232 + .../templates/01_px_olm.yaml | 13 + .../templates/02_catalog.yaml | 37 + .../templates/03_subscription.yaml | 11 + .../templates/04_vizier.yaml | 100 + .../templates/deleter.yaml | 25 + .../templates/deleter_role.yaml | 77 + .../charts/pixie-operator-chart/values.yaml | 75 + .../nri-bundle/5.0.87/ci/test-values.yaml | 21 + .../nri-bundle/5.0.87/questions.yaml | 113 + .../new-relic/nri-bundle/5.0.87/values.yaml | 169 + charts/percona/psmdb-db/1.16.3/.helmignore | 22 + charts/percona/psmdb-db/1.16.3/Chart.yaml | 19 + charts/percona/psmdb-db/1.16.3/README.md | 267 + .../psmdb-db/1.16.3/templates/NOTES.txt | 40 + .../psmdb-db/1.16.3/templates/_helpers.tpl | 45 + .../1.16.3/templates/cluster-secret.yaml | 12 + .../psmdb-db/1.16.3/templates/cluster.yaml | 615 + charts/percona/psmdb-db/1.16.3/values.yaml | 593 + .../percona/psmdb-operator/1.16.3/.helmignore | 22 + .../percona/psmdb-operator/1.16.3/Chart.yaml | 20 + .../percona/psmdb-operator/1.16.3/LICENSE.txt | 13 + .../percona/psmdb-operator/1.16.3/README.md | 69 + .../psmdb-operator/1.16.3/crds/crd.yaml | 18967 ++++++++++++++++ .../psmdb-operator/1.16.3/templates/NOTES.txt | 15 + .../1.16.3/templates/_helpers.tpl | 45 + .../1.16.3/templates/deployment.yaml | 98 + .../1.16.3/templates/namespace.yaml | 11 + .../1.16.3/templates/role-binding.yaml | 41 + .../psmdb-operator/1.16.3/templates/role.yaml | 166 + .../percona/psmdb-operator/1.16.3/values.yaml | 99 + .../speedscale-operator/2.2.203/.helmignore | 23 + .../speedscale-operator/2.2.203/Chart.yaml | 27 + .../speedscale-operator/2.2.203/LICENSE | 201 + .../speedscale-operator/2.2.203/README.md | 108 + .../speedscale-operator/2.2.203/app-readme.md | 108 + .../2.2.203/questions.yaml | 9 + .../2.2.203/templates/NOTES.txt | 12 + .../2.2.203/templates/admission.yaml | 199 + .../2.2.203/templates/configmap.yaml | 41 + .../templates/crds/trafficreplays.yaml | 514 + .../2.2.203/templates/deployments.yaml | 132 + .../2.2.203/templates/hooks.yaml | 73 + .../2.2.203/templates/rbac.yaml | 244 + .../2.2.203/templates/secrets.yaml | 18 + .../2.2.203/templates/services.yaml | 22 + .../2.2.203/templates/tls.yaml | 183 + .../speedscale-operator/2.2.203/values.yaml | 133 + index.yaml | 285 +- 780 files changed, 95863 insertions(+), 1 deletion(-) create mode 100644 assets/codefresh/cf-runtime-6.3.52.tgz create mode 100644 assets/digitalis/vals-operator-0.7.10.tgz create mode 100644 assets/kuma/kuma-2.8.2.tgz create mode 100644 assets/minio/minio-operator-6.0.1.tgz create mode 100644 assets/new-relic/nri-bundle-5.0.87.tgz create mode 100644 assets/percona/psmdb-db-1.16.3.tgz create mode 100644 assets/percona/psmdb-operator-1.16.3.tgz create mode 100644 assets/speedscale/speedscale-operator-2.2.203.tgz create mode 100644 charts/codefresh/cf-runtime/6.3.52/.helmignore create mode 100644 charts/codefresh/cf-runtime/6.3.52/Chart.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/README.md create mode 100644 charts/codefresh/cf-runtime/6.3.52/README.md.gotmpl create mode 100644 charts/codefresh/cf-runtime/6.3.52/files/cleanup-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.3.52/files/configure-dind-certs.sh create mode 100644 charts/codefresh/cf-runtime/6.3.52/files/init-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.3.52/files/reconcile-runtime.sh create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_ingress.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_serviceMontor.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_init-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_main-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_sidecar-container.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_cronjob.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_daemonset.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_env-vars.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_storageclass.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/ingress.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/extra/extra-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/extra/runtime-images-cm.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/cm-update-runtime.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/job-gencerts-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/job-update-runtime.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/rbac-gencerts-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/hooks/pre-delete/job-cleanup-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/hooks/pre-delete/rbac-cleanup-resources.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/monitor/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/monitor/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/monitor/service.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/other/external-secrets.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/other/podMonitor.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/other/serviceMonitor.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/runner/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/runner/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/runtime/_helpers.tpl create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/runtime/cm-dind-daemon.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/runtime/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/runtime/runtime-env-spec-tmpl.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/runtime/secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/runtime/svc-dind.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/cronjob.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/daemonset.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/deployment.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/rbac.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/secret.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/storageclass.yaml create mode 100644 charts/codefresh/cf-runtime/6.3.52/values.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/.gitignore create mode 100644 charts/digitalis/vals-operator/0.7.10/Chart.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/README.md create mode 100644 charts/digitalis/vals-operator/0.7.10/app-readme.md create mode 100644 charts/digitalis/vals-operator/0.7.10/crds/dbsecrets.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/crds/valssecrets.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/questions.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/templates/NOTES.txt create mode 100644 charts/digitalis/vals-operator/0.7.10/templates/_helpers.tpl create mode 100644 charts/digitalis/vals-operator/0.7.10/templates/crds.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/templates/deployment.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/templates/podmonitor.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/templates/prometheusrules.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/templates/serviceaccount.yaml create mode 100644 charts/digitalis/vals-operator/0.7.10/values.yaml create mode 100644 charts/kuma/kuma/2.8.2/.helmdocsignore create mode 100644 charts/kuma/kuma/2.8.2/.helmignore create mode 100644 charts/kuma/kuma/2.8.2/Chart.yaml create mode 100644 charts/kuma/kuma/2.8.2/README.md create mode 100644 charts/kuma/kuma/2.8.2/README.md.gotmpl create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_circuitbreakers.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_containerpatches.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_dataplaneinsights.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_dataplanes.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_externalservices.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_faultinjections.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_healthchecks.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_hostnamegenerators.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshaccesslogs.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshcircuitbreakers.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshes.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshexternalservices.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshfaultinjections.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshgatewayinstances.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshgatewayroutes.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshgateways.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshhealthchecks.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshhttproutes.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshinsights.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshloadbalancingstrategies.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshmetrics.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshpassthroughs.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshproxypatches.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshratelimits.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshretries.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshservices.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshtcproutes.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshtimeouts.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshtraces.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_meshtrafficpermissions.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_proxytemplates.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_ratelimits.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_retries.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_serviceinsights.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_timeouts.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_trafficlogs.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_trafficpermissions.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_trafficroutes.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_traffictraces.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_virtualoutbounds.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_zoneegresses.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_zoneegressinsights.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_zoneingresses.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_zoneingressinsights.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_zoneinsights.yaml create mode 100644 charts/kuma/kuma/2.8.2/crds/kuma.io_zones.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/NOTES.txt create mode 100644 charts/kuma/kuma/2.8.2/templates/_helpers.tpl create mode 100644 charts/kuma/kuma/2.8.2/templates/cni-configmap.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cni-daemonset.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cni-rbac.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-configmap.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-deployment.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-global-sync-service.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-hpa.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-ingress.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-kds-global-server-secret.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-kds-zone-client-tls-secret.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-pdb.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-rbac.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-service.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/cp-webhooks-and-secrets.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/egress-deployment.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/egress-hpa.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/egress-pdb.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/egress-rbac.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/egress-service.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/gateway-class.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/ingress-deployment.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/ingress-hpa.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/ingress-pdb.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/ingress-rbac.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/ingress-service.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/post-delete-cleanup-ebpf-job.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/pre-delete-webhooks.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/pre-install-patch-namespace-job.yaml create mode 100644 charts/kuma/kuma/2.8.2/templates/pre-upgrade-install-crds-job.yaml create mode 100644 charts/kuma/kuma/2.8.2/values.yaml create mode 100644 charts/minio/minio-operator/6.0.1/.helmignore create mode 100644 charts/minio/minio-operator/6.0.1/Chart.yaml create mode 100644 charts/minio/minio-operator/6.0.1/README.md create mode 100644 charts/minio/minio-operator/6.0.1/app-readme.md create mode 100644 charts/minio/minio-operator/6.0.1/templates/_helpers.tpl create mode 100644 charts/minio/minio-operator/6.0.1/templates/job.min.io_jobs.yaml create mode 100644 charts/minio/minio-operator/6.0.1/templates/minio.min.io_tenants.yaml create mode 100644 charts/minio/minio-operator/6.0.1/templates/operator-clusterrole.yaml create mode 100644 charts/minio/minio-operator/6.0.1/templates/operator-clusterrolebinding.yaml create mode 100644 charts/minio/minio-operator/6.0.1/templates/operator-deployment.yaml create mode 100644 charts/minio/minio-operator/6.0.1/templates/operator-service.yaml create mode 100644 charts/minio/minio-operator/6.0.1/templates/operator-serviceaccount.yaml create mode 100644 charts/minio/minio-operator/6.0.1/templates/sts-service.yaml create mode 100644 charts/minio/minio-operator/6.0.1/templates/sts.min.io_policybindings.yaml create mode 100644 charts/minio/minio-operator/6.0.1/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/app-readme.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/NOTES.txt create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/certmanager.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/deployment.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/instrumentation-crd.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/leader-election-rbac.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/manager-rbac.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/mutating-webhook-configuration.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/newrelic_license_secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/proxy-rbac.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/reader-rbac.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/selfsigned-issuer.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/service.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/validating-webhook-configuration.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/webhook-service.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/NOTES.txt create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/crs-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/deployment.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/extra-manifests.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/kubeconfig-secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/networkpolicy.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/pdb.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/podsecuritypolicy.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/psp-clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/rbac-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/role.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/rolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/service.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/servicemonitor.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/stsdiscovery-role.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/DEVELOPERS.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_affinity.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_cluster.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_images.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_insights.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_insights_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_labels.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_license.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_privileged.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_proxy.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_security-context.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_staging.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/NOTES.txt create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-createSecret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-patchWebhook.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/psp.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/role.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/rolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/mutatingWebhookConfiguration.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/cert-manager.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/deployment.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/service.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/deployment_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/job_patch_psp_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/job_serviceaccount_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/rbac_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/DEVELOPERS.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_affinity.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_cluster.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_images.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_insights.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_insights_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_labels.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_license.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_privileged.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_proxy.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_security-context.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_staging.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/ci/test-cplane-kind-deployment-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/NOTES.txt create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/_helpers_compatibility.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_affinity_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_agent-config_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_host_network.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_rbac.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_tolerations_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/agent-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/daemonset.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/rolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/scraper-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_affinity_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_agent-config_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_host_network.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_tolerations_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/agent-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/deployment.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/scraper-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_affinity_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_agent-config_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_host_network.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_security_context_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_tolerations_helper.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/agent-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/daemonset.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/integrations-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/scraper-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/podsecuritypolicy.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/DEVELOPERS.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_affinity.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_cluster.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_images.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_insights.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_insights_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_labels.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_privileged.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_proxy.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_security-context.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_staging.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/adapter-clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/adapter-rolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/apiservice.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-createSecret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-patchAPIService.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/psp.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/role.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/rolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/deployment.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/service.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/apiservice_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/common_extra_naming_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/configmap_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/deployment_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/hpa_clusterrolebinding_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_cluster_rolebinding_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_clusterrole_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_common_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_createsecret_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_patchapiservice_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_serviceaccount_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/rbac_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/DEVELOPERS.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_affinity.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_cluster.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_images.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_insights.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_insights_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_labels.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_license.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_privileged.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_proxy.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_security-context.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_staging.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-enable-windows-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-lowdatamode-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-override-global-lowdatamode.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-staging-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-with-empty-global.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-with-empty-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/fluent-bit-and-plugin-metrics-dashboard-template.json create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/NOTES.txt create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/daemonset-windows.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/daemonset.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/persistentvolume.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/podsecuritypolicy.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/cri_parser_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/dns_config_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/endpoint_region_selection_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_k8logging_exclude_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_persistence_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_pod_label_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_sendmetrics_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/images_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/linux_volume_mount_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/rbac_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/NOTES.txt create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/job.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/tests/configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/tests/jobs.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/DEVELOPERS.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_affinity.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_cluster.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_images.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_insights.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_insights_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_labels.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_license.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_privileged.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_proxy.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_security-context.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_staging.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/static/lowdatamodedefaults.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/static/metrictyperelabeldefaults.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/statefulset.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/configmap_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/configurator_image_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/integration_filters_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/lowdatamode_configmap_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/DEVELOPERS.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_affinity.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_cluster.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_images.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_insights.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_insights_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_labels.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_license.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_privileged.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_proxy.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_security-context.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_staging.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-bare-minimum-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-custom-attributes-as-map.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-custom-attributes-as-string.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/NOTES.txt create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/_helpers_compatibility.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/agent-configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/deployment.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/agent_configmap_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/configmap_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/deployment_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/images_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/security_context_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/DEVELOPERS.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_affinity.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_cluster.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_images.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_insights.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_insights_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_labels.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_license.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_privileged.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_proxy.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_security-context.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_staging.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/NOTES.txt create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-createSecret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-patchWebhook.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/psp.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/role.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/rolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/mutatingWebhookConfiguration.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/cert-manager.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/deployment.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/service.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/cluster_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/job_serviceaccount_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/rbac_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/volume_mounts_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/Chart.lock create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/README.md.gotmpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/.helmignore create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/DEVELOPERS.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/README.md create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_affinity.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_cluster.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_images.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_insights.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_insights_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_labels.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_license.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_naming.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_privileged.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_proxy.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_security-context.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_staging.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-lowdatamode-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-override-global-lowdatamode.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/static/lowdatamodedefaults.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/_helpers.tpl create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/clusterrole.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/clusterrolebinding.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/configmap.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/deployment.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/secret.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/serviceaccount.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/configmap_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/deployment_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/labels_test.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/Chart.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/crds/olm_crd.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/crds/vizier_crd.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/00_olm.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/01_px_olm.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/02_catalog.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/03_subscription.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/04_vizier.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/deleter.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/deleter_role.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/ci/test-values.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/questions.yaml create mode 100644 charts/new-relic/nri-bundle/5.0.87/values.yaml create mode 100644 charts/percona/psmdb-db/1.16.3/.helmignore create mode 100644 charts/percona/psmdb-db/1.16.3/Chart.yaml create mode 100644 charts/percona/psmdb-db/1.16.3/README.md create mode 100644 charts/percona/psmdb-db/1.16.3/templates/NOTES.txt create mode 100644 charts/percona/psmdb-db/1.16.3/templates/_helpers.tpl create mode 100644 charts/percona/psmdb-db/1.16.3/templates/cluster-secret.yaml create mode 100644 charts/percona/psmdb-db/1.16.3/templates/cluster.yaml create mode 100644 charts/percona/psmdb-db/1.16.3/values.yaml create mode 100644 charts/percona/psmdb-operator/1.16.3/.helmignore create mode 100644 charts/percona/psmdb-operator/1.16.3/Chart.yaml create mode 100644 charts/percona/psmdb-operator/1.16.3/LICENSE.txt create mode 100644 charts/percona/psmdb-operator/1.16.3/README.md create mode 100644 charts/percona/psmdb-operator/1.16.3/crds/crd.yaml create mode 100644 charts/percona/psmdb-operator/1.16.3/templates/NOTES.txt create mode 100644 charts/percona/psmdb-operator/1.16.3/templates/_helpers.tpl create mode 100644 charts/percona/psmdb-operator/1.16.3/templates/deployment.yaml create mode 100644 charts/percona/psmdb-operator/1.16.3/templates/namespace.yaml create mode 100644 charts/percona/psmdb-operator/1.16.3/templates/role-binding.yaml create mode 100644 charts/percona/psmdb-operator/1.16.3/templates/role.yaml create mode 100644 charts/percona/psmdb-operator/1.16.3/values.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/.helmignore create mode 100644 charts/speedscale/speedscale-operator/2.2.203/Chart.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/LICENSE create mode 100644 charts/speedscale/speedscale-operator/2.2.203/README.md create mode 100644 charts/speedscale/speedscale-operator/2.2.203/app-readme.md create mode 100644 charts/speedscale/speedscale-operator/2.2.203/questions.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/NOTES.txt create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/admission.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/configmap.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/crds/trafficreplays.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/deployments.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/hooks.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/rbac.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/secrets.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/services.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/templates/tls.yaml create mode 100644 charts/speedscale/speedscale-operator/2.2.203/values.yaml diff --git a/assets/codefresh/cf-runtime-6.3.52.tgz b/assets/codefresh/cf-runtime-6.3.52.tgz new file mode 100644 index 0000000000000000000000000000000000000000..36d424585a0f5513f7c9ef0d37042d648fc3c74b GIT binary patch literal 43593 zcmV*9KybewiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0POwia@)AlFbY4vbro33yfwC;kUIE~jJ`GNdlXr5H1R>NBxhEh zsgz8Ukc2TsZ~)4VCX=f74!-|i?OnAmV_(mE1N#)qA&JB3DC&0gURgLM7Uy4 zEN={H1N>D2000BrAkS$43hfy|!JNMYz=6~z$Y($rplpu}2irH07}qo8I*|$SXkx1VN_(e2WAgB$>q=M19wq8=f_V4bZ|491%z-nPqQg*U-3ygz|p=_^+R9 zX6?06{V}sJfiAQtlz^jERyjNLaY!@cjmf%UVt{hZ=XsE)@AP$;E~3XyRH?CFqwiK0{@sH z0-b;CvRy_Mc!z1w0OgRWnL4`;QM{y(fB@e>4z}*yMjKD9pbDxjRnhMzn!h zJ~DW(WRV*<*Y;2Cv!X-Ow(-mhK<79y#a@7x<$-Gm@HO9%9Wa3e<_&e-tX3=m%1|R7 zzCa$E!h9H+OefxU9IXCIL5)iCgHNzy%wSD%4WkzIkxdP7 z&Y@y123fA`V`roW=p|=aBka2Pj*YWG8E~$44Z(~;2V8ym0?ZF$a|}mZ;QaOLkbUe4 zmS?iYsBhU2eEoXGI?Yfx=i`;^f%a)ZA9~`Aq|M{?qOzzL60Pih#6G5bQt=e9uusSB zZm->H4%)|Zh%#7|fc=ku`~#d__6Oiin}NPXj#zh7G$s~bs3U@>;Gf{g{47OVDZnY( zrx-v^<7+X42SqZ)7Sgk2C62%<7y|Viroc-`w(vqHjNp^tDluDPTj3Qz9u1)7l!UGq z+aec(lXD}2K%n4*YQ}qz6xqmyP7!Y8ZO^)Pp^!j?wgCX-@0T!SlWKrkxM2vT70`fK0UWcfe8$z!zI@T(I&d)eVFUEA>mqL~^i#b# zA3H!(v`c`!X=<8xxDUt*oYqQg5KWMf!hg)HxrwlR8!3n3*eY#?V`hyTpk~&pW<6}7 z$L!MrB(8ns;{zweFKW30-RjVH!rK(lU`i~KDkppdu#Cp%f85?^xav@dx3{W51 zV&z6+8C&;EcXkLG1;Bv;wB_zb1z3SlIP181;@)HpS1g@C*Nu~yjjCw!RzdHzTNmf8 z&S`ttIUlrpADX8PuwShv$gfYhrsDw1agf+t7%XsW5n2*pQ@lvF#aPO(7rpmyPcMEQ zvL-Kkz4m$QV*?yk!3!{$Ky8)XVRAEa@g1-U2JzIr7Guq_Wv zEYEQv-x@4pxh`}~a4dKMWy-^0Ra-UW7TGYAY%~S}02LqQH$f?0tHscP>bnwB_;-#e z3|WV)pj3}!70!csF)!LCBl;@ZCTqo+0?>cQhN$fC?O4)XN4H>Q@G@cP9iRNQTRLw4{C@>sZ$ej^5 zn6M>?U8eyK#ftV2QK$5L$P+Aawm6?=NOs92)FkAL$i8+Rz7&wYd4QO z=k0#K0S;0Oy!)XQO-8oja}eWf+b5XK^?bg4@Hc1M0)`~Bpl^0xl9jdB0Kgk+T2t#! z>{)k|o2(goHY~z48uqVsM;pkRHX8qIwptgL=YwJA_+JfHsPfNF^K96=IBgHln`iBR zmA~(uWWTBeAZ;TFUyfpL*5#)@K8o0(u^a?;+Oe{9_g%m+FFT&8+`q9*E5}&0gi}%xRE?WlE@! zZ)5Urjaq!%EZ0XK3_tNf+Ba*j!y!(R0)#6( zF+8!sV2Xk@3$U2hSNfdb({$!vffm8uFZen&tKsJW5^t@E9dF{1C%0@RF}=-dYCbU) zbVdmD?0FZv$euUATTHHzBjiUp<_%EZtJJDsPyDZ}3zwsr`wPCN?+_IT?S~R9bYdTB zvKIBB7t>Q8WVMY_95#pXX7lLGRTN`_$z{bimlvQPU}BA-HdFYnk|90i%?~OdG;~gU zZP_=_b0iop8iJiG&Qq@{SMZvOe+`?WtIE~bh7O`PSCuR4&lwSavl%I&Gyt!t!yh3R z(m4&_RKbRygM+Ke)#nlARY!Ed#nCc*FE{c;R|y61vo-Zy$a@@T_*fjvy?@>3q@{X` zJII74xRU)gC6+&n-iei@O#e5tYe+m8K+63luuUs$#zH@!6F_N`!|u%2M5lSpTH7J*)Hj7S4iZY@%A(RC$r1=38C!352$I||@61#HA<9$my} zXT0U3AEy_S*@X1QMK^d&E3xmfgA`6q{twblzckyAFlkm^Sa;Nr?S>4duzm}#X@cVI zH~qxK9{Y7Rjs5+r$`!)3tKH~GW>=%WoRVX|Ue1F^fpu#k*Sbb76ZHPX9!$d03;Z|s z7{nPhphW|tW@&(>QV2bp%=sBebQZEJ`6&Ow7*XUDq+#{`tgqL;fpdQJ6$f%NrSIW9 zI-%0)H-GI9o2^#6-ygnje;js>b2v*9Wa6ZBy)n;GwG2Pn@&z^dCJ=QYBHx0ejAX~m zB&dvoiG*^KS2$E=xNa5xV$x3rdHd~FuRYL^d5$C&1Z=7fuSDil2eTk9r}m->1t_jT z(%3Lu^W3}7)SyZW1K@s4z~B;v{{77Q3=B{^dZ{E0_Bxml zJR48^Ss?J#(Hw-|0P?^YdQ+hqg7*C}tkn-Q5Y*6KFhupWhe*@kV@$7B-#@UfZO5q9 zt!rcdz;=woBRDeH`@^GGuYamq*AaQ*+~(}#`}W7qaapr>Bv;DWM=|x^w?Ae}G081? zY(udf$M;Pa&m41%@z{mZk8kSF0w@0^Xo$9qNB}aRH%1;@elcc>!pu|q^8uS*&S?{)6sNTy_2M;XLoXnfTQlq&GoT>DUq;OA z2LSkzd;!XACX^eXECCFqDYE=BUDPM|cW4JgU>I07Q>QF=kcRZS50svsp%*-)Fp6=X4BzmuP?a|y_pHm zAMKMcW?1$FdE+zezy>&1oaRNwI`J?GCU8cu4~?2ErR+(0*)ri{AXb|YP)d>ARv!2lIJGLtvN8KWWWHxQtJoQm#~Nv$ z$(+HroGJ1UKb^`OezvrcH#V3iXc5mK*oD+UUVx2Y0u9@p(SRQiWt}*rO!(i>$%Qm+ zLoXV$00ZPrAVJb$tUtjs*8v_5z%>N&@`?$%@mfgu91`rh&`J7uP~<=}a(Zij4xs0R zmRn(ksL0t-nar;Vaw<2k>CnY@!|;GM=DVle!zd;1%545zMo!QL$1^*OXG3B@xKZwn)$In2$mY9`_s@&yBzAFNxNhun8>iCTxA*#XLaS;sw9))Lf z$l-3rs%)%l-MD4&7XtQ!lIWh-U&YS)zZ;{=mruY|GKd|A-Y2zh5y}qQmNyp*7^sTvyqfJEL

6+w_aDP(s@e^)(2p_7McoI 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 G|M)L*&dN{# literal 0 HcmV?d00001 diff --git a/assets/digitalis/vals-operator-0.7.10.tgz b/assets/digitalis/vals-operator-0.7.10.tgz new file mode 100644 index 0000000000000000000000000000000000000000..596aba80a50b5522c29553255b8b14bffa736234 GIT binary patch literal 6922 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 Q4*&rF|CJ-v+W?vX057Pj)c^nh literal 0 HcmV?d00001 diff --git a/assets/kuma/kuma-2.8.2.tgz b/assets/kuma/kuma-2.8.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..9a60b081cb148cd7696c4d61922d77c4cee434a5 GIT binary patch literal 69514 zcmV)nK%KuIiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMYgciXnID7ydFr@&Fuo4C)E{5#pYulHQVRuY{!wwC3zrzgA5 zfk;R~O%W^s+EJ5y_qQ+rNbsj9+i{XzvuiaL2@D3nU@$Wn%v{C`+&!G*NOYEX;s4`H zJX>2^TL*i4@bA{vR{r1Z-QBH!Z0{ZHZ*A>8-8*>tkFD*U?Y*skpsg>0P40=gz|lXp zZrxVCbKl8>gMbMvC<}P6g^-H{_SvlCVj+Cep{(nYNYE)IUJr#h5&?-yi+PlXK3+Nj zUXUJo9WQWcG5MK?*d;wADbL|cF36&^XheL1InfYh=@t&@FC^lW1wC}N)52kx{M_k0 z>+G~V!rh350$%meE8;JZD~TITS%k!#0A}cr1tMZT8u>UNtvQno%!LSfuiKqbF^?x5 zmo2)o&H113Pm8(|G2;znZl!$?}>-9`Cgr#7T5TU4j;b&sz?1 zb%P-^xWF_JmW1gzV^EMULN58SJ;mU|6&_JJ^w%0 z+1e}c|Gll<2mXH_&&+2N>`T^97kEbG9|-+`90whdDUN-CA~K^~L`z_y*!L9+9m>)i zN}B>b)b^NrNg~O;74K}P;Lhg+c^ag^vn(`dn{T4)Id$iV3Qqi~Db0~!sG~%be!}qq zu)s5kFu?D79(oUOMzQaYi5n5Y-^;qP70LPyPsXmx;y`c|bK(IWfP>2xAqz+#xETx! zP!GNPz14z-ew`CBCy|64V&TpKw!qPh2$XDZ=$Z=kMeT6N#}neWpu!m5oTNLUh+@)e z(SQr=`-hRoPlLDNEW#d1dS@Edg-}4Q(c#$c;d@F9&oXytYS!oz_RBIV2<^`_SL|mC=LP|%p`&aVc^jn z0DL~D98D?lC04$VCXz0~h`3k~577W&G>t_Z5u_!6O%%eva=uVU5o{-qR^vJID3@IY zs+ddpV9wYjZv{*W3$NtgJv7BWC&j7}k-S2f-Q0oQ98H$U#l9QMJ_a*{VTj#1aW8qi zNaPLPILE;(p#TjRq>^Oj2f-DMSg;_0Kw^$XR+d1N%i%^e*p$OFjeT@I zCqXg=aX{s4V;`w;%hhH9x_riA{*zXEsC^kvNE8r3c)MlrIFpF5xg| zo=4>r!wBnD4kQo2KZppc`aSgVa{^MyVk6|U8S=>$@q36#q^5{Xr<*jGvQ3Xn;#mvH zBFCykTfT3X!eFroVAY5W4jE zOK7+6c@g0}gX~GXn2<;!7!eSIxcobnaYr3AoCPeBt6!1?js@c`_9Zryn-$+eN%bDu zPJq9m0bRrk6eNvs;*;QR!#KKR)R-ARZo<(M?A#jfN9qA{)mJ=TS~fppHO5ANsgjl zTM#nDw-WM*c^Qx)^Gad8Vv(F!fqgV$9_m}e?6P1=XK|z?RAf(qwb5D}Momf$NV7#o z zp$X)0BnO7;eU@EADVR`0R6Dtf_=8I-LU44D34;$=%2@4 zG64C7qj(U)z=XV{3YtKjGIGunWscp&LBgUGtparuPj2_J8y4UN{_r*}ZFAB7bV>s% zmU6ds32fm}?2}bvVaZ8ydnbYBnH*sx$RhNyAe)FYv}7@IaeyK+B@qc+f*1@4$Te3u zq7osFBo7W;KlTWK#u_U%lEBsk?Pp#h6avhMct^3^*~adic(J5)y{D+xgAc@wfv^%P zzb14x7d^DSwUrQ~Y(v98C(**DVGt6sRAnAH1Vk>XM9NNxRf!gA*JO%wr5wMLfdaJ$ zA40i*8Y`FmIOvir!IaR+lCxZcxv~hcP?9K%dT1CFJ}Naj-+*f5@yCy55~O^!z#R#{ zjXLP_=f_P^0%1CE?-;GlnUb?RQYEQH=YEF6$;j6>HiCuBXS3yNiBEQD=8OxNv6T0y zvWSOL6anEwM3_p&?~5!#$^X+eCm5QMK#q zOC#7VVxg3bYci2)3!;nA2fmUrCZ(MRf2f6$D78{Q(l0ga5rFPNQ?gyH9;^AnAyvYJ znLa5}q*Dnvj^r-L0xgle5+anCIbDU zhjzCPo^4xb@RfM*FNerZtA776;LNVx$?iQ$(MupCdc!GfSJ?NLh+UB=q8`ag^BMZo zU3$z>!lXcAuppaWL!T-kDTxS#h(jgk3`Z6aTSgWPN##m&+X_&*(*y(?30ufvieZ^@ zH^Q>Dwj79dX^{}dy1jq!Y)dOU&{%&oL^$x!%eO;BgPCOKh!Y`~1Mi@>O82ExSdP~? z0G&h4w?r7=*dVm+L+XrDCxK2~KI2B*>%e+}RxE*IsI4!rpK&zQIGBl6@}X*xLld&8 z{%BY$d}t_#KIU91&NLug6SC%lK8ci_Bw6c#Yh;U&)PiyXgph9lCHxUqk^W(odxJwc zCT3)hcMfmCQV=9nfUklc0|tdTzLG1*Wl=8G6dJannSkON`;vRLkT$^l4-3e68MtGc+g5TDNs)%5 znEgr{a{gigL3|mQ&gfztG!%+nK$(?Vw^q-=2%zZ@I;12fImjtk4J>0NDq~@_d`8(U zoGgZl%N#T8J;%NjVxoFB$YHLQXgJc=0}%EmOXT`2_9V}^qMlqEvRg*cmYwk#_Rz#` z!?zk8j;tXsY0ilGdQnF>m=Ue}$xR-+uB2Sq%ldZ4Q2z|7gEo^gRc$K6zP+e&{8bGh zlGK7ExtMV-S&Qg%t70px0&=6RFuM)z-=a;ecIdTXLyDMSF7vZ=WWh2BCJQapHF{_k zg>DNBKg#S^zOeWu4b_4$WN(a>ZwQ~OwR=fJ`Qs2u!J)4)f8?RzSg-|)1EKqdXaC?0RYXh|)T)s!&`RdqLq44ncj@{h*@n>*ZGwig9nVwd@Gv4{!9uXJZ^Ci~ zC^46x`@fD+|MDUb>rqsCfNzFWvrRW5mO&p=$pU=daU-z_e_WC!dMDYmi{(qj=K_`hu@4J6vVv}= z<6;FIv^mArDDi#=EaiG3uAHm{jyit}94+`rjbRZ7=2Tsk;t4>oK(FeD#u#2+W38sk z)kkLma*6iFSQi)cM8lP;ycC1LWJ$R>S}{OCj0hv*5>J^#q!J(rLb4IPZFq^jvuYI6 zE^lba_PFMU;W_5yU=NYNWfJ&dA8EH4R}$M3uwBUMz;IZyqR}5zKht)f$ARakZ5DL1 zH7F`O@Tp|Y0`%(qd^Enb2w1O{2VSaJ)ce4kc=`!(hXq|Am5+oVO4l4T!_jc~43 zY+(f^pfW4*8()EkeKdiswnB7iG!iu{bvV^?ZkD;3Ds8C*S`p}qL?E&yJ-?*kFY?_o zuZ!gDb5f9%8+^tt_n7DXb5dKce$mhClO^6@#<5{&oNSc&SZQI&&mJ01PnZ}f39VQg zprVL`j8nm)rPfl+&z?F9aNMw6(J~Tv){!$Fz)&UPEvzGT;vk37Wg#V=GVExFA%PVS z0-v$OZ-Y(#Ag*58AJHJV>LF!|*wkw${SAi>>IeF~p+6_%j=AkalO6PzY4u5!lgsPd z3wrA4lX)oNs3z4Hq*_!iMO`A?ZdsX#VDB{Wms-8oZ_PoO{)sZ+9oWS`r5|&jp>h>L zD{Kt~TNs*GDMBe_TZ76|BCj3LZ;i-dgvJ?4wOa8il6nSSa=ZaHfJsb!Fs-;T7i^In5e7)G&?r=9@4!iG zXR@(mM`G6jiO!7Mz?uj`Wy|T{%b;mUS{v;N*lV&U{g%5KxK%2>e$Kc!A>x`vm*7Yz z8?oM{8^3XLmWyAxZR(8}{CkYOU8=0$I$)j1bkG@b*Nicm#&NvSy+Qh4T(>48UM6fGT1J}eOps7Ob=RdPC+fu>*}cP@*2 z#y3^}%+(naHR+~ZS>K}(_#H@jAt2(2Mw+R*0qx3F5c6(8M8_)wGNC~Rz=Q@0z!i?V zKAixN2@T5XX5250`XpbTBo~PsH=rH)%G8(j*78S|uQMKXo6;gqT}fIMKN8c;xSi8ruqzn21pRD5D*ca%}509g`CrgPf&ziU~Ouk;o!-~%dy;r z;;_V#Ip*r_g~am-`4Ezb!m+duw=b;Uy%g!eB%EfpW?9)Ti^%iQi)6gjEu5B-G*?{8 zX#_Geg}F&wkZ2N7Z$=u!Gb)&xJJjClJnQVkM!(|R3XZL|(_<@hD7C${ReEZb{l4Z_ z7|`ud;-~FqbNM&G!gq;Ke<<7P6I$9)r~deoBIW}d9YW?H4T?7l;7Xp zc{uyG&i?nd9&Y|T-2C}IZ~pK`euv`*Ud*V@1#pR^liq4g5IwPOT~F~9i_rV5YWQBVM9RvAEhxLNjav+NtYS*A6vbo)`ym%BRlMvCP2I{Uge$C_C=(g9k-(vPwRhy8=6 z&k8mNczF{uNs7@OoCSO-$B5$Ia1TD+NzD{rZ%%^mjSM0xtUcXYUAKbN8 zPj0EyKPZR~3gUOAAl|!0sfjvj$L><@E$eEdgS;}DUUo&_g(f<T+FnqE7U=;kw@+A&d$@$e!G>p z5T}AlAxhh;!SNd%x%7_YlnlfQzp{oNG?CZUF2UVk&4qp=2b+9*cd(AhB%C^~PjC>c zV__5!;&F5xQ9+U@5Xu}9F(x1~y!I58vYM<3K%|l|i||63FCgBlR1hY_XV-ccQKpcP z2@(hjYjqM4e5tA%99*^teIkgzR6g-sMbyMnLW#N3Ks+Wva|RZfNjN=Jb$hmQwC)7z z_8ke&$W*1nTJ58Bs|hW%Uq89k)2l5Nc~`q1&|$_))GUXr51X8ch0%OOgaaPpNXok4 zP^*XAj=E!PbWqb=aM3|t6K`DQ20=rS?7rG%wrg}rQrcLxpnsCRZ((lSU_aU9&22x4 zk{(KRS~ilK6$lb+s+0@>Ys9kQXaE;*lGfN`KzcwIw9n$e>n7GYP(pK2rxHR{W> zR7fJ^$R{)GF5%X_r06t^$TD!}5erh2kw<)iUwb?o89b$LWt9vtm~USv+YaK?BQB13 zM@gfJQ4$Lz1#+PSdnM(swmUojlyZ=&cgT_q8EG``5#vJ2YL8Q|BZ++)0mt7}l^9`XP#JW0`|{rc^j z{>AwG^lWf3Ivtl*VD73wi4P0AF$-`3d>?7@chL+&@{|dJ<~gP=9 z2uE^>=&0=NP1J_#ugen_SicT&`uB_2_tlD0p}0*z_aD&UYB*K;P?&f=cz)rN`sr@ySrr=BlQThU5P8ERG*m0Zih0$)2n$;0zyAISe>OhddIM#Ry% zL>w)9IBw)|=MOfyaekos{6E_}ySsbY{69Nedj}8sf9~b^_z@zOJi&p7I=`qqP-U5D zIwo=?lzb8}krcO5r);1n?oMnWjN$H3L zp21lE={Qb?B%%p+J2)0|7HPexbNLJmYYDOF^W-z;lX6O_jCF1k>Ay8eKrDeCOa~4r z*z9!|9n{7ll@enBl7}AMwzk$~1W#F71r#tJAZRi*C%y<>k!WHUhEvnzCkR~0FLfa# z`RP+Gk{>f7Zb=Ex)s_ASf~X(}=94o5Rx?8oH6z?YsJPVD9#0;F|A?l;QbvzZ69(Um z#pmfKr4kcd<`%@^s8px?``&JDOg?7N^pIT0A?fgW4}DS!@_%$=9(5-)=#tSF(J6X|9FD+V)|J)ae<0lazy_%O=%Xz1xm`M%3UdWRq5xO-Sm~IwGZho4 z|EGEYr?jy4CX(}~eEPrGqP^wn^(~H7#qOx8ArxomZB}CCjCDOmgG$WI>`C zIlUs0I{tm)QCFaL;*iot2mAZGdmFg{tU9UOD30UyPCAgNOzKVE=K{K$2Rv=t+gn?U zcK(y`xotxT_uS`PwD((qbJ=2nC2xJF_bV-+baPvD`**9-74zc-c>@V~vuHS(AZ!Vz z&*7upp^G1K(b-l&PGzYg@bYh^@TDel*nA;CWQgKwD6qyUixyagqi7rIqv}^m>99E~ zN=NO8G0{ekHnRGzd76=ZGiv@fCFUx+Y(kZ#G}(~os!6VrpsjVs=j~0@cHGPo!_kZv z7o{!rCB;>*O9;1!kZV+!UJ3p;&|%U?UoUzCr+ZsZ_xB6fF#ze|Ns8p!PbNQ|2`gV|4$9H>JFW;_TR=jUc&*5 z$L(4=R1u~IbiC3Go$p?yw{3;`W$%h*jaWwHOnX%p>@Q`yUZ45p*1sD%CWx(r15d|) z=C@-7_3M9U_v!9dZv8*q-`#sy|M&6e^&c<+M|V$DqJq*Bylj#om6T?qaSbb>PI}-s z#neab-&hRpwJMNq;Gqc1=y}$d<{VCbmCwm9eed0~J=?x{`m6&t`zUaDh90}e{ zf)pFpV)2{8H_dT6BJ^9WUx^CIiDSWL_9#RAu9%YudDK%$P3Ah&Cyfxh4z!0;X9Wn8 z(ZLvRmqa8tU_9-*c#W6nnxIQULMuN7M-w8h2?>`>0}+2S5fYB>3|ZS zlT3BCSg^nhU2f2F-kq>2PRu}BK(G(vz$FMsg7qZzKj{3(+nHvHW4Vzl-{Dv8>N>dr zK0iN}&F>!UZ)Jx^zMYZaux|qH;&xg?mNZ3WAx&*F5{&6AARfH1F$t(|^*4bd+bPbt z0oegCpU~uBj|6UUu9I@F$+B21GsllyoP%aDa;NUFP0?~o-Tcnpj1fMs^z2Ah)*2oi zm6EC(Rtl-6ZM`B?^DvG8Qj@-VEk_OBD(dcK2dTKT(di8wa>`CF6F#l&vE_%~Z*+e0 zUllLU+^kqrM@TmYlk_~~1Nt9i^72t7FOAGjc`A zwH`|_#awM`lgqRu7dx^~m-FWk)mMJ?Rn{zln?dj7Zv3W~TThtC+;24zPTsYxP~RF` zosus}qJc8$3G=k5zGoslpoRzME38R1?AflZ6H)8Qa#Um}=3H%KKb+%jXJK-_CcY_Z z9CQ9D$?#fpi&P%QWKJ^$O#`j$Xcr3}o(=lvgUqY9qa*uOsqNHJF4ny8N~bVLKcouf zBXtzGi5^|qQm%IK?il}Td-%-0ew8)nIxx{Xoky-X3A~kW8sU=$!2NOvaq5x5bPE0; z=!8L*A+yRM#fg(#`FL37-~KYsO<7^Ne@iR9Vp->|He|l#Z&YMH=59S?zS(ykR&$Kp z2X(O^^A#>GBpO`iQ+jbB`&wOF$hl$#Qr;Te!)+_eYCCHtO?Zx8 z{IDQcbX#^^)o%m;gG(1E1t#TQxVVGUHQ0Tn~86s2R!K@EY+X2lxmnJf4Y^!_#Jz2??N zGmFJ9D%axO*etFRVBd(XBFQBApuc?k%TZ6(x2?F8m?-3{qrvgucIu6seF)odM_P}i z!fr|nKc(kv@6F-by{!n4{Y&!rB^+Hu8(z0-i9P=CSLnT(O{OjoW6pVCq&%Y(SY59 zN>+IT-}jvVC;0;I->dzlLz1L;#2hh zHa_xqw)|JE|Ly(lr}_22y?^kq{_o?-t^b^Dzm^*mHpSGeYSMo;U<@lYon~C3u>4AU zf^W6jbDGFathDAHyGH0xZs*Aj_FB~QH53k3RGm5FVl@~OxzR{Vb0Lx&d{Sz%gd!zG ztpX@Z2XKxT{;7paml~&hOmnNZ|^_N$N$^i-g)5v_wmRjG=;k}m5#z0d*Md)g@#Ly zzl1_6*IY*@EUK0v!GMr%5g$L+aPYDQ%6zo7yacOK`TS=;RZ68rvKKxFAh+T7RZizB z+1OEu>$i@S?V+nJ3A*O8baM-aNU7OxGIp46@Cz^W^ErMpTxK8fmX{%Ywq|Az(S5R9(3 zn2o^u#AYUHP5;U1SAC(|5`X1(jekAt+#I!6L|*5I|*j zjw9>}5*fl!q>;#uDK^l7h|I``H;^5#{r|ng&R<*3KYxGn&e4DUWL|Cj=aYZ^t5aKG zi3o(PQT^Vi9`WdAtd$7hpj6 zIQS`N8Dw!BRKRFw#>R?6XaCCm-GBrVcH39Uh%$U2j(oWi;>aK2h*x+w!TlF##-O^0*|W zZ-|v0Gb4p?L|wQ$4sq%9XYFkT7xOpKBPz&37O{~tfC4SoKq1(<(I*s#A&F|*;zSf) zD@Y2A%DYs8Hi0Z={E&qZOTi-~guknXS{6!%&D2ugK)nINH&f_R)JL66rhCH?JA0;~CnrD9+TL)Y{zoD1Q|^Cfm~A?$tXSn^>UM>ELkoxI6p``&{5w6;4+iBD89bhoKeHbn>NzJmf%s5J$-KQo6N30A`ACeqegs8xpQT7_jMZg9pw_L6{eEU-_>luJo1n^!+4 zrs^OS$}LC%DhWbbz+%lcUK$y?{t(dQhPO!1B!-7*%b|~+l!aX0K#y!GYgL%%tO8t> zH9G}Roml%8STzs!oS)crVm?Z>VGe2&QCBg$+U(a2=cak^?>h?|!s^H2CI!o?ZndcS} zm9rH<#0CqODyk}yx@*eVP)h)zjIG^Q^iwkU*?)?UM}$x>&p$v?#wbfV5eBl1aN zJDI|-^8;5p7!cGs*EO{O^0Cf!R^;@BU+u~yMnl9AWM z+;d!J z-$}2_Vbvx8xB<2%ckW$aTZFaVBxM*`GjU6=>Y6Upuk`F%RuvzE20x80WC+CB+i^I{yVgI~;eERZYcrrfkpBxS@`bS4+gYmd|_okHiUPag7 zn_AmkU=c$~pW$eQ5D~>ejl58`JbX4gmIaFaR<&6y!dN&V7V|n7r%-H^b16l4CYOXP zDyEr9R^SLS-0vSe+scimnmdo;S-`lUZax=G7%{Pu8A#pdRj z@>Kx$)K4az25Rr`?d`V9q@wli3fH3k^x0~e%coZ)Ae@gPHp#j5>Zo9e&bghPiMbHr zOHy##)wjLWjsE<`8kS9}+`Z_Rz(E3Th{1OvA=i3k`gBU%rR$UY4C~j)?UiEddxd7! z70%ZUY+EYl)>`vdTbR`2tPlll?@w(r!&bV{^vT@9*F_v5o4g}&Q3oBb5_p?Pv@68! z6%u{}sr;^SEDGBz})llxvKJ{Rkd$7#i65HEa z=9(`+9aDoug0H4pYZYlfX2@Z4yY*ND=|-Kdcb2c{*`>$tfXl3ga^oIVxt`bbCv`Qy zO@Hd4tluAFjQb!Wd}y+F*1M7=#p-QynWCMbWOOpUE~%4zEmllBT2jw^T+be9d&F4= z((!6Dq+PICM>92Qx|wjaLM8oW)yQP(tT8TW2gM?+A=UJ2E=%kksN;8~j62OV=rCe` z5LXZ{YkbKhp55EY+I>pRHBQb2MtQB|1`#1dK7>^HCM0I1-Gi;XnK3aV6*YdRD&H$r7RCI?D2*XiRWU`aq=bV!b{$;f$m@@WCD7|yt+QXNCwF(a zs+eW$&V;@KFVeaW6$@23$lY8QZJ^_+irG;}fz>$QtZe+F$$fU`2vur61#q_*(JGO? zstZ|Z{w{{K3WHLQufmJ_vzdJFH2U|WkK3#3%~bW<^l}vjt2@<5LvN^^uhEl6&8~@k z{Up@stT#pc&eqEsdS`Q;^KJ-hB|_ERZLD!N(>5FQr*Vt*NHq#93ecw;0+1jMj`0}|8^om3i3)LAB$=^QZ>5pqH+<95o>pE`7w6_|vK-UBI zD0kTviI$m2=Oqo1zzZ1-1oxBV4Vm^#x0b(1F7%9M1HO8!XIo>is$+iV1Lmn1E)<2gr8P)d1yWvK;#7F4XTI>hG|5^?g0-52Y30e%3OTCt>Dj6h z+EwOJtIU{Indh!5$6aaqy0TPp<=Ng!Gul;Wv#ZUfm-(oqDxMK@*Gd8Rv6ySEm}l){ zCMR|F@0+A~yH%rKpBt}W2W4}Y-{VTlOlg39`j<`Eid&R@NtsUm>mBWs)q8@J>u=v^ zUhWTQHi%F8&_7cp-N2pJOo5hA94rKO=Td}qJOZIdk~MuNL{v{FIHZ!z1i<=M2pew9 z1zVU8w?%ec-3=76l7?1Lh$MtsDk+1h5zeS+KbXw9M9#2s$3PP@Wf4J?^Oy!Rv^YN= zBW;W?AMRMpNg$}(M7V<{B1jlkCq3OxeSb~^j|Q`^p~W+wXfF>lQZ>l85GtA;)<>1c zkmy@m4@xatX#Jyzq|Pdv)(z(B4s0x6&f0cUOH749;u}+3a`vEmMDz!#*?A;#rYv%N zIwc6A4^bBAG8~PV#}N$>XA7c)&P6JO-C(yY>!QZzhE#hutmO+5@68y{_sMxau91%> zfBqBDT)?|KIAd6q|7CY;yAc0>YyaW==RO|GN3BfsePX-hk`Ez?s1#qZ-yxH5YKp

cY5&OvbPv=DLwdZB?_n23{~99X{}HN$PYff=5554E>CyPfU!ruhgX z(NoCFu}Hs&WmxgWXR`|k(jY(Q#>ooLkXEqHhI$EJ$rpvUgmrQ8`t9?<;pxeX;meB` z!{foIfBx#?A^~K&b1|X8g-4^3_9rwrqLJM?R3aZ>k}lH2nsyJpLzx7$=yzR1DckD* z>u|V-r|v19|C=1}_m=;0cV}y_kpFS_=>z}2k4ME@uRB0*nhf?HlRe%(9(2M*$|EM# zjz=Mhq-8-gVaHL^Sh%^PVe6*}Y%6M$DH^0il1R~tapM$Yk5q-S!C^Q`qS(xZ2=f58 zGXP`>Cv_051=7qBKGTu*3G*PmVpYDmWG)gfQrR4YbTwHSHM;uE>JeNCDmPWu*z6R> zhBp`-e$S)B?{Ij^V3m+^O=O{(GzRwQ?(OZC4X%lFlpSJ$qZtu*86>G<($?#0X%MB9 ze4ZX;dbq%ek8(W{7KCTn)g3mfpXo$4zWdrS**~ro{ayQ1J&15$|H;XJ`Uv-Kg}@c^ z-_A}x|LgX_&h|t8?|XT2$6h5VzjcY#+0bs1=S(vKm9ytJ79&1qvF`%HI6;p1d6Lf=QTPB8)2GT=% zG?D_<@`lPxmmi~Cx~amzf1y-VnF5XJu32KL1o!*NNoAV*_R~>WbN(eWQKbZq*2zI- zuk{@JA>$Ui6bOWyQ8cTIZ$_$GQtep z9VU1(135Z9x;W{-8Du`*Mbd#x9H!c)$D{t?7jC~82P%`2;qdh2{Ot7jVszX;8C<+Q zJ1)bfhuUC0?RC3ro@{lhgqz;}!P95$rg$CpFAfK1=WqyLj$ma#K{s?$MFMg#TKq*kcSThLaC z3)=aQ(8xdkxs{E(HpSGBBXT~E2%j_G>!Iyz#tLv2$NmxVahkXGARF#3%x)6iP%{kvJ>g$_8BNDkJ5XPdkvZZ<$b@80O?)uO1fAR&~e^&bcZ13go z{~T=X>^<=R`*?EvpH#X3G;;lE;LS5=;LNk0`wl7h-XUMid53&4-yQM=TzANQdhU>h zjyvR5emf0nui>^sZtJzPlMGLZ*G}1plsfH@8~N<4sC65c9rEC@^EY^k`roC;9m%Qf zpwmh*zNt8{V*lSN`2Xx|?LXaq*#Gb2Q384G-IGkhiOP8HnIPjG6$zncx0Uo{ZML;p zhKu0yVezd9s`_R@BHXXmlS&A_Wt*jMq~?i;2D2kANGMAVK#0hnF^!0a+DjIrMa+fV zW3H%25Js0ChmbPu#=}hD_DZr(uYac^xBkP3I1mBK_Z^5=;UprB^9P&Uj03D#|4*Mj z&B^~e+uM5&_y6zZvBj2z>H_wP_={JJU2;_8&R-j8Sji2KNEET?4dGmB!M&eRyQ~e$ z5htR9eltsAfrA+P{!&L&0rX%Qg07%$hNr@|VjbobM16HEQT$(R5yj+R?IeVgB5o4tq0+&kgy`Rw&pRvn0MD45XHfkrI+Nj+wk@+_=5^%so5oX4< z2DGQ_xRptBWymRZ1SsY|ZFCa*y5eV9tO$BCBSp+Kz;@Nxwl@%rZQDk%ssnkA&gY~| zHvqOXE*~M)>4LA9>~R>;Kul5lM{XDwmmI5&o|H2Fja8apZSeCl9M(_(3u;_@PW(lO z&%1NRF55lSw)k+nSi(`kdK?v>P?lGe?Z8J^Gn56J@C%NSiAOy3Q%(-?+AZ75u_)mC zjYF>Acl7gn4Pb5)(%)cm?mZ}-D2JsrdM&!G{+w|X0kiN{Qt{W+O@28S@Q6q?N*I6W)8K`2k4uKFssF!1bWQL7IzMq+qg8y|JlbE} zj#UMLuY?w7IuV&sE}|v+{JC3GC}f-p2E}@n#RQ(A&!5{_2b2a5;7{O6%;^=0t|Kal z@n4VPpwHiO61CC6{{HUXMs5JB{KPj_JBk-J_~iYcG2wZaR5|)#+(Yf{t*u4gbrLPe zfu=dN(xnls>Ece|EP^ z;(tBd|Gbw+*?%A9&XYps9Z?>|q1+ap$KH&HwLO58DA2vyE;#=rUlL308qg+0;2Mzd z*|q>D=g}eake74{O`umC;fR1yM(1`S9-1tXm{Trw5(yl!Daxg-&pRQFio><0szL7P zLhOnYWFyMtueKIX6w4?eTdV9)@m?>f>M?tWBXpZ5$NzN_2nTW`-B|6E`Hm}=tRPBHF(A#g!kMZHT*^}e{C#UCwaYuX*ciF}Y z{=d7obCBczy9fIZ^8dX&Qt~^T<4AP0(F)BmM-xHszxK~gh9@suAe#OKnO&RPtLWi{Dc7M7nN^_2D4wuWX{;-p&fg^jUvKB7H}%%?kS5*ej*yo z>O|z!mIE#6~_$(RDP%=0vE?z8IMhSEJ(ViKrZ3)wL%&wg9#K6 zIqx`HA}@~2$-1GQh%DF@_Ce%W(Aiv|kO>k9DhCFDk}D#cfn1V+?KENwJ`$vupV)u?nec6pFy~*rWO(uhl%#(RXyuolLHPbt#4uv8g6OQ413) zBncMO1#+=6$$+yoWam25lY5kA=R!{o&yM(pa<5Ju8Kb8!`o#SAp$xLTRkf74J!tR`sE0Ro@s~s@vCrqt*L#A%zapX7w)1!?(C3A|y z&|e~F+A8%BugY7IO>bf4y#Sf@&L`2Vw`3m4^U;fRjjF*a=NIW(6>|cM$Q;+eIgXmf zz;bNKEoo*J%O-f@HyQP`NjYT5aa^C^APyZcXgi5<+_D|m&H%RcyrgnsG%pXG5>OSe zC2L-9+4AO{v-!WJEL-&dz4P=xEA{`UTlx6E`+NIa5AxrAJaF|RUf{zpbsnqsa;@^2 zO0)jl;@)Lt!k^Vf&}fPT=*cbrB+i;gcKZjau8i{`BranX)cMnQU!kjJFo^Y zwnus|$T%_x!`brV`AR?U1ZDnGNY%y-xdvXvuuvzjln?_So%0mn)ThqgaNFvWT_OQla$U9RGTd!9tdjh1;PP{q5dc>3 z|DBzk{Q2MB{{BP!_j`Hj(;na0LAEZj+ZWI1_V;p9RU=yCR#rDur7oZ7UAz5zrL$*M za%SbT*%(e$9@5nHGk<5aQj1HD3~Q3J-r4NjFw^O+Ch4BCCkONnGnYb#*I4O)OYQ6H zKjr>EcN+s}mHxNCTR8uH$p3dwPx;0Czfa_!dv?6Jhp<0MkE-JRl+1DCNIzwD?KD_@gMY6E`73n2VS5n`2W+L-TgxTr~QZcZ};-t(*M&wKevv> z;r#pu^lEVY22E+ig?75&>aro5qSx^PgR4(~s6Zm3gd@R>Z-zF;b-DC&<=-om);S!&$&0vMHOEdqe8$BGEz~Bg&6uj;{y` zNu)CdO903~H@^h6OOvr6;$XR85s~em&q<^lY_5s!v^mDty)p=JCX0Xvi~6A4W4KVL z5|n0NYc-5`kS^QrJLZAv#5Z*<`tM~;&Qj9%Ja6^U43ae9+D#>AK`k{|rz}XX>n+SYh6W8B1?m=N*&_mdRzjfGy z43{>~SB`qH?nQmohr;W6=k1a!_7o(3Ct$*vvN-TcZusABgRY%%^bpjcF}Ux}g#KMW zMgL!=-Z*?2xObEXV3q&Z!9m{t>*?;nga7ZnJWcFBnHc{SA%NA_|6u_cF9Uac_fhw2 zTDwIk{u>0;Z_w>K39^5?{4#~m{0-2q4A zBhFnlr=*TfdA}OwE@*&6HlG0w!%>pbU`;@}URE4l#XD*!%}#@`M%{*)5pD#jAmA%z zq_;!}5-#_}^^+;&b1@aleyx-W#r^+oV?X_)$@%|YN&dHo_}};PA{Pp9X?N z9m={<95|Re0Sh3veh;lpK-@Z=EX*351Ia1l z@uI5^&@#001RUDXqt3a;u=5;qGQwhx+Q68ykxAMc&@!Lno&5tIFYE)a23FjFN~NY> zW~psxt1U4Y*=OcIKp?G6gnbsw)Uh;#MT#f{1nPSp3;1c^FRi0!G$B5_-b^4YaCFJF zFQbRBBwAP3N7(Zm7HlFCa1~^W3M6&eq;eQh7E!T8+?^9IhOj_5@RWZf72FOY6oCUG ziLP{9FIk^XB}j5bB7lp?6?FyiI=X-X58)-1OMnSR&OG86Jgbi8VV&QnFMw?D%XtEn z0Fh((244~ct|%%jh~|E3K=r&353vAYh#BP(-m%W|$#hCw(L*O}tjk)br!15$vZ#j! zA1F^IUNswC){+ebC5cE%8Fs6eWZ5gB(;ruJA5ddAAsPN&~u}e-Y%d z>p;*2F(K!$;fOj88bK^lZgZ3c{~HP7`{;FI&;c)9hA?VRS>%!gys6Ocp}7zt?{&MW z6-aJ39&@>5W-bW@?_RU$(r4J?-H@sOb$<{fTF?MU!(mfLelUY=eR>&TmyAe6!3Bf` z9`B+3wcSWGSGy}G5|cM09dKkkNJg>m8@HF-?yX!ua;38F2v#z@2KW23b+rRafk37# zT3{75tZh6hsQOjF4z;Ch&_<6o%9A)m1bZ|foR1F-D9SMAnN+-3zvy(w+WyTbTVRtccg`autI1A>HpCM{;_I=EW6UiY8h%0^;QA~0L zB-e+^xo;(@^#j`R+3c8H5g)ZZGKpvHEWQ#Rye|V*=$%ie#9g|6j)cRAj0FqxbXG=^ zwM4nVm!#yi<6IIFIx|LtSs5w&1P7}yZ{|p4k6V>@)N1Fb^#hHVVWd~oCo|&pP?OoP zxZav=k>Dyj{y!jaw$%4Uq#~muftfI7%H6e-^Kw&c{qSUXad>+2;^L(LW{{g8kaV-| zfqHPK+P$-#L*!f|prer+LO(Wef( z^_nabgIe}!rj{n*=kgE8LvBDXbQdp5O6GcUaWp(@HnIT`M>HxK*Wnb1YE$0^(qi0P zlDKE7uA7L7IfZ2q&s26+)^m=t5f(|0^tfr-6$>}R{(N_Bd1tE!HHOiXCP7c&~xh1h`90x_6s9d zpsSRC#UeitHj?RAMKT$M?=4qX{tWLsJQ;Qha&RrIP_Qy;di8zq^)HuO zdGl9afHt%Wrbk1t-|Ic-bPaw}*Cqd67okfj>TfX1cNh^=2jjeTNKiYDr(>s1Nq@S` z_m!kqY!Gg|R=4^Gn>1)u>C=so_$o0*|E?5!PvKEZhxfa`&3!wn`C^y4^R)K2z13Yc zKj`6d_t(ALol}byHgbXv)r^%L#3isRkMznfhOYoycfMEXR_(2EOZ_XoHhz;+x019z ztIpq6j%}r}zxg4;>XE+Pi9$2GwoieaH}1xMiPYj4FJQ zqgrw)zdWNyRz)eWYjVmrP-?0-(O@LRjrDp}7qFvQ zC-ZmkzhFNrq6IYSwYfWVgC6RtciXWXJ`H<8Zrlm-1^Pf5bwTn6wpg%0n?)+tyfKSN zM2yV`_(0hOYQ-Nq=IY~$d&?=y&Gp_EB+Thk*vUE)Um26$$B!$jTN<-90!4@m9N-!8 zoXIk4!qWs@I)aJurgjYTU3W^`UujY;sRIgRP-b*2pYW4mJ*L*x9gXB_*YX-mS{V+S zbs&}5z8;%!J!En>+NE{R|bIDIZ3qW zP9lUnN>t^N@|GHH)gT{2;tJv!jiOl3-t}Q1Hc|lt&d`*zX!RHgtX!0z1f;&y>XtVY zAo6E}Dak`C7%n;+8!a==5R~Uh3nc;}7*3Sx2DTF&kcXom(@;D={)r~BKtJ+AM<@p~ zmSE_|KRaklN(;eP#3IBmX{hW8a4l6TjygLx`jP)+)tItKd9c&KqgT|6v5#D~2w6Y^ z(P_6(N-u?pwP>S$66}K2Kw29aV@zHsKgTn*25Os1SJ>*APn!@1wp?FXFjn&$CF-=f zv6HTPwORpWzB?s$D;$wP41%k6K^Rv_Ai_vlaWN2I5f3vEHD9+a?p^pC1o8fpoJUua>MyF@ztNWJZ6p

i6FFO$|KwRdwaX> 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 literal 0 HcmV?d00001 diff --git a/assets/minio/minio-operator-6.0.1.tgz b/assets/minio/minio-operator-6.0.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..dd0f3a77273ccde7540d35da27c06ac22f579400 GIT binary patch literal 24539 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 literal 0 HcmV?d00001 diff --git a/assets/new-relic/nri-bundle-5.0.87.tgz b/assets/new-relic/nri-bundle-5.0.87.tgz new file mode 100644 index 0000000000000000000000000000000000000000..e3bee6fdabdabe17abb4c2cc40290346c82e392b GIT binary patch literal 340784 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 z z`LPx^aK@(n=Z=7Km3ZWzo8tQ>Tc6{BgeI7(HPnn~kyI};>hGP+qMDmdTq>d6)?y(k zxf=*XUz+MZzv$;x>tzpY)s-zP$k%tVQP90oa@NadQ!Kqn(xW$72m1(wbxvCv|Mtjb z>F9{4^<!9?#JFlC0Dpn?lqqGBb-*pp7ivo*Ew;JQ}id2#9v%sveFq zn;_x71&0?X;UWM84)2bQ0b|Fq_D=-9AG3vxjR&jX#G#uf5cqgIJwN(Dw3DOq2f3DF zfXPHcS=cXNCoc=)*MVUO>JW8onw863oKD-+zXX#_1>eoy0(wG^tGdI)Gx;W|+{`3S zG`f$rBK>p|jk7nSj=Z3KwOmeye-U&~QYQx&*>r zAaT-0-YCTxI>^Eo*PB`LkYM|$>yNXRiwb3@plTy+=z^THb0Ypl(l`aF)rM2rS4wU( zksy_yj4=6EH>u$F3|q7Ni*|XjZH+}#>uG=*BY-HwvCE|X3}Dn-7u5*pvde7=#5+~^ zwO!A>&5vdUty|wnfTixo=$Ofbsivs;A&!JQ;g18&6?s2zXb&(_dU=IEOnJh#k&{T> z0`$=p2I_IG>wIYg679b=q04lTP~~g(CA*HoOooK^3iMQFiwGk32&u^OS$QT?->R8F zwR!<^|8Lk0UA91Lwf+!j3tkOdu|dB7+c?jnDSm~(|I9@(QMm~Q&k7$dLSn`-seuU=1Oa`NR+3^>AD1|9l{V@_aCs<9_z*i* zo%J;>SDaN>U9NhSq8Ozlr4kDa-u4dwdiWfDN@a&Adc4m8QzHQ-z)G~SpMeJd<7LCO z#zM@#7te+8qRiE_1AWnkj+9jdkVc1aRZA;({+ zF#HI&*m^DWvsr{_k|eIb{zZ0>0&s%0t7v~y$okcN1Ny3isb!oZr%uaDhP%*#xQH1t zVmQ&*=B>ZOBcthx-iPq4xECsKm7eEma=Sanp6hl&X4;d5Y%1?=x6 zd(FY+R7~|F`wjs6DLl>CSWt=65DD4>y@0D;R_L8kMjgV4G6Bnde^pzl(BHU0vkIuu ztK+hXuB*Z*TSKZh{Q)zYuY7>CQXaIRgh~!WGGU|m{AfI(#WDSoO4#Ep>9#Qf8v~pO zaJb}3IX``Z1{Qnf8-W_VLe%9POFToX_-v$1yQqiF?HK*SU|aAUSx&451?r&>htvMc1pU*_Oy@j4tX77}=yu~;ivo3W3#qt5SA4-A(jp4&(-TQ; z$yR&c;OCv8yJk7RRLZA?CG443e?7z~-e0=zmXwS1rg_1lI2V3SB5Co9u&M2=GSnY) zFm}h~=CZ^d?N}qdG_77%GiP86$Bz}YXugIFaYvdE9uvwR1gv+F#H{(5d}Hx%SWceXlu9vn_)9Ct`ar$<@%OxL z=46|x!id>Nrq z8HPy=FG4KwP8}ga>5o>N)~bp1!L9`>a)zW8WJFHz{oYg4IQJ~HcNyr!(C5P#H#kxn zF8GSi!@#FZqjE#eoI~o2yAFkqBpoRthso?3=MAGYM!?`Y*^Yl;qC`!7yP;Cj%l%M) zCm%p+!Ensw8eJc=dO)RX*+V5mcy7&oik60=>S=@A#l&|88h+6^- zq>ap-N3^4@n&t}j7UIz4QqNSBUHVh>di_%5UPT!vpjEP+A$!$ni0leHT2rRrF&O^M_0go zZ5~a@H`&@>yWyc^P9h9%9mGN2??odeX|mk#eH!a;0Hu_%+}W{Ex!kE$J@!MC&n9zW zeE}{?4U8R&tK64z>$ye8b?{ zq18`tw*P{2F)z<3IlZsXodg?1B39}z+)V1EI*^GX01qD4PlcT03%#q&=Z(a!JK zOASxGFJ7f#py&O0;EO?yrzS}7uBHnK8-oM{?m-coi*~)TU6Tob*lvJwGF61&)u+3J zZwk6`XC^w_W&bbZQ(vK_y*mU#v7(8CfFKr}(IV1m z?3ZpS)!JJD<`|=)6d>v^#?+MJpbfl`Qer;kt-V1W`(KUOYXCBvj#fwH>`Kp^1E!5dhcWR5g=F(9Edaq7nx zwLE5i#n;S*9l^nWi65@dhcx!HG!UkIXz@7VK9D`OexUV32t68gPmL;96*W@*omLlk1jv|#6oVhfU@w+ z>gm&TMvfE`P^ZxR3X`9!6%xb*)0zL%%%GHN`5@SDZSxLgxflYaxVjO&-@w&ZTP5h* z$iJJg4c(HtxaO~(Dj=>3-&m!ByQEW|$D}eN)Qx>=*?tJda!%YWhXVAFs=T{gmkY~wg1I5L-5T)~g(dMFmiEF(6|85Cb2pq8MsU}WtndeD9tQgQxc zxq5W{F|Ny8r9ZGlA5n&+_=%V_rQz!(Ale7{w@rkhgV1&@>ONz7ttetUrQm@SQ8Fk= zP6-ezDy*UNrAY+jSl6o70NQcCa|1mP$5w*s|5n|yo;ULcgQ3C-AoL4LmVRjaJVA@* zoy0duF5Am&W6i}1cs&=_sWtdJF;&A7)F%-ox*)w_J45p0^SeHWr{*Nc;52YK9l$~J zM}n=df;?Hq!H+8>wiW37Z#i=k-&Wx1)0EvOyFvjz=H*zsxJy$NRB}fJQo?X4&O;Q7<&IC7xmOUE6P+Zfv@}i`Rh}`+_j)exvjqv`#bOMPQ zuNN7z#qsjIXtW9a5;BYT1VsNziriJC6ZWGt>JezXq#HYE23nVfq^KKbT?`PH#e&MC z5QJ63kc2UZL+VFq((syBllAswj3*w{^n5(3HzGh=IIyAgtUV73<@jvPgbM$@dA3{D zx49A3{+`s{(ev|eOjCRZY(VFqn+ZK)oQ!)?+@m%5{qF6*dY?p_k!dWd*3;|)p68aF z@FxLn?B8~Yfv(_8M(^hOt}hRWcjzDobUXJ?l!_c7yYbS0)*r@zwUm@vUfh5*I?*#x zKq;rUJ@r6<)+=R1;NA1 zsg)+r>hQajR7GrLhq|U7T{Tt8x#3M+KYb3SWF$>zCq4Iyvxmc^CXGo@h3K=7)^j5g zfh8BU+mG$ppgLY!4~8m7E$riN-YW2 zLCokapjr}OchK5`(N>jkZ)51_MgK98y|Q(1s6Kc|wG$YRF!^VyjkenMkNVB?IgX;| z6Qx$guS$^RvHI0=zGRuLBJIh{{uIrPj_F`UYE1HWjkUUUXm69@!JYXd>oVv}9-2sn zDnNzRU+R+o*;Nny0CatG#Ww=-iYpxf7Gk^a`~UV+B21?^#l{IJXUaijz}N~-Rno*7=ID(Vez!()cL&2d#fWmfI7*5gdt_Fm_JFO4Kw}Sn}}8O*rdGKuY3`n#hDXpZrX;ihr+AA^&t>y+Ha7NwyPjx9E9dTP4> zrjOtUOXdsE!oXtgKXX4&Xf4v~MJ+d)CNw>YO-2c~r#xq|^3|}$fNT9AV`gKW6A`M2% zXsWg-&#&Jk#D0MIt0p03c&2@ny^6A(MUGBTtk#p-`<4qp3uaC%8V>jPcYl9MH3&Re zG63-NuYvt4cmL^;)(wEDE?9VE=vB8-(t^<>o=pmCj9^#;wy-aMk?bXdxU7*BC2@4b zM*5j#DE!}Q77stMxFpUO)9W~84czDzXeyElI#x0=u#D%wxOM$0-@OJCy~u1|s{R7F zuOX9p^vB?lfq80mf!2#jGG;5|Z7R5JO-4 z3?m}g-_zIH9FAD2UNP*eCa{3;U>2&>x0LMy07gI%wbmk-)?YvdX%!=ab~T zJs;BNRh*Z{DOD!{FJZ)dXd&xzWr+IYpkV+sW{Ui&SB_~p+*|zVYg#)7%Dw4!I|N@l z1c<+JO7|i>_1-aguHp8|6#Dr)OeYJJ^Sm_E!UybdCE*uTi~)*8FWCaOxXrZ^dr4U3 zk|*ef9A_3|RPR0vF_rS7j|A})r|MwNg#i?Lhre6mc?~U%>}LIPPXlORQdfIISw-6~ z+hz8|RSGg;T*{&+!u>(oUCeCqVl<2)mOpK@6evf`0<%NZXTd%gauO3P3yu5-==)Va z#Dvij)NJ-p1u+X*gQ~$3*uw*m!YtRTFEf+6J*D~tC>Lu6H}I!iael2YEr!i{HcPZ#mh1c;#&}UcXPFv^3klfB& z3lydK?{}4Nbxp_9n{Ta>Cdf1PE|>7QTpc8gnN85+E*64d-SjDSK7mV-w?MDi5?nx| zW}VoST=~=@T~x6>nYj9#zZM&^9-*TdObz3|GDjsd`(hC$D5l@cv|Ioxpjq zz?iT}pFZDfK88l70?~QBSh}zDfkw3tsY6DqcA!#jLE9&u!>_xHhbgyXAfkVQJ*fE4 zqB-+lsPNk(xJ?Rk60&0dARu)|3KgGBx7TllT18aj{w`LMp4~ShJ=hao0B2<-G3dpm ze)**w;`7!9sheQ~=^^d5)avz%mPzo+R7dpamJDtAkvvFKUYhn{u|304 z69UAoicJXbHE^xJG-R=$W+Z5d*f|W3`IV66%4y&sciR7B*k|R!1dBI=W7BG^;7$*; zwO`6meZ^m@1`WTYmTR3$WyOf2xVgppZQx~C&yi}~mW#4Ebuyo$#V#rcC@oa>PCbP% zZ(Ul)SK9MnUjP@9nzSRDj8G1=eXhr!pY&Y=c2Sijqic$gL;>8nb+l&nTM2E9ur1!_rGCwX%E!j1jy> zPZR_#X+*SR&BAdrAE~3|sG!hzNQvVtu9VcJ-33KwRKM z7x);Za53Nh<(?LcQ$j)CT$@cz zSBPmo{YHmWs^KN!h-nd3$Rt;QX-+L?G=4CCGApxEy~}o!p_=L~N%{3xU>Wxu1+-V!U($T}8Y zc#m8IMxFvin-I?;$^1qvJu4RSdwQI7oCXIl39>Cy!))9VjT_u>z3-9@Gu2S#rVp=r zl1NG#KhALE3sp4IBvrI<`BB-hOql7bl@rnN0E$;Vw3RY>OkpNXeh?abml-Ng*4WVhX}0 zNti}-43QKY85QSwn^nM{&ztM`K|8|;JAqc@q3Om7C!-fn0ulZi$q zooGt^u)(ZQY@ejuE%8=w?@qwWOxV)iASt}H?=~HF&H^cZj~#IbAlQw++1i5KnSmb< zfq`Oxn?N4X4?QMS6E*11a& zjOjbC*eJ-ZCLtWQFAmOO%s&!g80x}2F|KX3?RGp;G)NX3iy7`%K>HXu`l71d?8jPN zztkO(S<_!r{5f@5kbZm4z&6pQrOm%6o(a@;i1 z0Q0zt)h3o(2ahCaYy&Gd8!(c@)uQ?vmRj)>kD|-)3r(zh zx6`Tzpsww=&Qm01Rx8zJ5{51aSiv17!Yvy#9}8N~nz_Fxe2JEWpkvY0FttrU&A#$s zpvKj8PPZoTeoxGv$X#mQzxAl_&+je_mReisN?Z`SB2IOWt=tPa|yzGTWen`xK1?h7nF(!}(+#|*Ud zab6yl!$th@bwPBxjID};E)_76t98>qbZZF#yh@$Zz(_M0a7LTS(j#67SxZGH5gMlA zPp!!1io1pA*X))1M3?{AFb#+F)1p!_97s8l?qZyrL)NV>|C5zmZM`Gsdpm}F#=mQN zmN!!VHaqfk)d&lWh4KKWBf9|+AG?90AK;Hl1)vw=4Iu?Yt)gP)6j$phpSmlm6PLMB4J~cu8>5Zcn zUAC++KU=Zn(zTRH0nQ=kB*TF}Z@O3Eplc4XaVH}|QwaIxug8ZCwhC?cUJ=AD zVgIJMOcEo{*dfwtt2V8gc$H;e(eWsO8=e9Nx2LXZx6w~?J2$FCYx}Dgr(jw#B3~_i zJf2|Prtn++WW3S=DH1PmMeCfznvI0 z4|hCxFt+iifWEK2O)32oq~kNF#48JGZ{?oMb-wlWSxzYgmwuKhBGm1wrz4q0G0K6BI zab|&Blk7WM%|=`P2QZt<1m$@0MzwRTcK70O8}Qy8k^1&}5o95+y+BW5d!}8`jm8g9 zh$H9IP=iGB?~hrZi4^va%2yJs?FEhoGvs+Uf!bObY?|be5SPLj^z>kN zU5W=QrE8()f6Xp^@iHRseF{!2Ut>Z$C>_{OvdHjdvl7;k7Q@0GP20UHJCYWW;A>`J z=?u^O{OjPVA@V~uFe?XY`(y>DN*1FK4Bqi!`4PAbw}WkRD|KF)fE7Yxpz0&-W9egS zfU8pOwDIyrrpKk>%h7#h$w1Lp=1NmFC+`78Dodf-@sPA9a(Z?%bmy@@1ByD^$Hx@w z|A(!646Yp__I65j-H$%UjcL;#0); zxiKHhUFd*$mzs`H)rfxh%=H`Rf+hd?)>&c@9B0&{f&q#mWAeR^s99 zefiAH1&+;9sy|h0I-X=#ux`OMJ+S&PvN4`DlA}y+z(-6#R{~AVyO@u8_Ihfai^j4= zG@i^zAF7fZA+#4OoHugc3QRgQU|_-QX!k>j#Dxie3?mbc9;=Zr76(a6vP?k(PPZ0y7n zfK2RN?n@WTopOw+UMIG*q>gv%n-YF`m(kiZUn{O8;^* zp=}CPHVZ})${_G+O7l@Ad{&to-j>AuLED4+HOn`JrUjr$2E@cn-16mI=W>txV!59m z@p0r{LZSihvN8Trmu9-Q>*bYCp;BEU?_F*_n@n6^dHp^`FsM^EAEo%;IqUD?C0Df+ z0NgWtOwI~GG$-S+_Th$_$iqaJJj)|mbvJ-5so||;&Uuf!?Te;kYf@3OQ-yf>_xE)X z@zBjr`0btoLv#%Cidjl{yq`fvaJ&yaxEt4Dv$u)TMf|86TV8up6$}8Gfr16*m8#hC zr2zQ)Xw?HaIo$66>r+YwZ1GPdB4?N^rEY*2aDBUVsN0?6@@ABG{{~qUcRe6DkN~FH z*t-XqIW%QF9cD7G@mChDAVur%3QBS*XASee0fu(<6j%F>l8X`ee>e0}Jp?#Au%cJi zPTbBPuDPNFoB4~XajG=dTZ{%|c(XCs)Ga2o&y!vHbxS4K)Q77wm1R07#X^pe=ASO) zg+|XXd!aEV_w6ahtDO=X?Q(|)V1 zJj2~qlJ9Fxn+`~r>&X|AbG*jY3;)H6R!3cZt2qubMUkl%StFDeAS!O%5|RX$smr2` z?5-aA<6ag0W77aezN*rMsLb-jRpuvIxt22vIJqFE<{F^+J8Qyf7nx!{*v3-sN_DtW z*R&CvnYGr!m2yJiGY(g6BT1E?j@erqqPj@4IayPV!r7*VGE?lM4nmmv_gpMd{?d$D z!VS(dgWe7uUiVVAd=kwY=W)kzolfI1nRVN@xHIsn4oo+6|A~XDAyLc-IQActL2ux)B8tuO)16;%M;9-6CCSD+t zJrV5emc)7N+P=51+;5I|i}uRHidcZv*Is}~4`W{5mIowg`I1(~vs3}FQefNlw$s?MfKsXegN2_u z?w`+axkrF#?&-VUjFnJvKt)(;m%xW>&*}u={9U8iSM$`A_Nx=tnhLPVt$PI2cX@Z} z3S5S<#dnIJ2XxGm4TSn@CxG~w53FjUR@otc4V zeoxtJ)_uxs;Yv$h?bkCWx>o_g-|^cG-!rvrvRCiXa#if2&slYdcZ%Hi3E!`v;YG8o zn<$!U!`IhZD}eJ7*Y{ntGu9}wv%qbtcr(G#4>dgP$sS3cz%LnS$!Rk1++rt$)X03S zP8*h1#|~Z|D{YP|U0_6g9GrGC4@*QbO*Z415wwFUv4+mJcgbv6cm@Kafd9tF#p_OF zjF7`GyG~5_DvwPv_56WHTTAPh!(bcP^+S@lx2rAbL&WWied2i!u;w+3_r6SZ zc$@Q)`$b`sz@s@A2fo^v6jhK0b)8OUqja6lSG2mr#FsnK>y8@TZ3_5n9j|MKdYg`a z%9jN-E64Qp{q&fP6%>7@cOL=Vd|)Bm#9ewrbshKo1%x*0&gk^Gd%D>FksBm&rq%(B zzR!9Z17-_92gyEqqq#MY#Qq6gC1l^ggi^{8bO5+F?|un0(vF;>MT(W59LD&I6*t45 zWUFb#41yHwfSs}8VBBKx!%-AU7nojdkbI{7Rt=*V2VGosvl0Fm*rR%-JJM{4?~Hpn zuRd%IxKZY-;VxDaKNQ{tdQ^$mz=?c3bW>G0Lu@^A32~mOE z8SEl13XqgSXVy%JJ#wC=eufB}o+@KSI!J%_mfJBncYLM7xQ$l|)b4#tOBhJcpYBZh z{wxFr@3HoVUd3O6jHjsOKO;fjnd#yB^#*{D3I>Ei5pox}p~v=y0v-NSa z0>sg=^w&gByh1{8qoAO3!Fx`#PmKnUa-bN?1{o41kPY_q=+h=tFs0S79{Pp~HsHYn zhrO4dTn!ya6=G`>&3<)u>|PiOaW+=e!KRI&0A;KTK9Tt#i|W zXp@)*VS7Qg95TN$Q6-q_497@ZGWUF*XR>@zec1A}xJv=ox<-kk_K^qipC$2*FcjH_x=7rUBm(Wn@yJMO!eCW=qvPKVCodsha`%!TXJ+ub4^5~RRjb8u z!~63@`}t1h`8abGaHi7(xE;L*{9*o;C$%=+*G_9=(|!uhr3x~`OIyC`T*Lo|d~L1l z?y)F#7ot-}S2Eu|o;Y(MBd-pGL_{J*ErCYc9=btYe8g45=%*WF#K=FND;_@(>z~hs z3IEUM!aWy$$Nl!Xcwb-e1Y4l{N;oGtha66bzAK1~Ebwwl7!n6u1vs1QJy4M=IqM9@ zshZIp1oL+!FYWJu6!ya8%p*3F8EdeOy((<8kDB~Y8Zhl(w&lfX++sf61U?)|*~#41?BL?enBC%^Fd}B)JGNcHHZO{9_>Dr79VV zQJ7!0(Y8BBT`-tNFr9?v*gnGh$EoYBmEK{O32{z3BJ{I>+iLAEb*rlIMohSA5UFEZ zdc0+^)k;vwbNtPN1k34Bis>rxwA)03+g0Ly{Kb9NEMv14BngyUM?(?^hO!u(p~`@F zY4@K;H{c9E235kpaTw%Y^3A~-TEv?dAjub?DO?^+QuYmPHxG*O!cc&!u!;GyWHa!gr=gqBj-3SPFyWOuaLbbe2^S_^En}u64l!{HROTS6a+R5acP)d^ z0>0$Azk#m9?Snt#(%(SW;6I>ixDwb%_DcS#J0sZtvY$d}koh_>$U80kN}o+qST@n` zRm1iS!k(CG1@<*bG(2}S{}}==M@|4?54FCS#z60!vm%yJ2%7dUBLHK7a$~d0b}p`jv;Gbn4)RCbm#-hwQX) zmD@Lyp+7;(d*G&~K+flVyRkbJ2fI+h!km7IZj-nhdE(hU?pMabeedn_{%JtV9D~%| zinF#akuu9R!mN!sYQt3Z&7Pin^zjaxZAgUVK3+3?2e_B0sj)OX0g2s7yMYivuZ)50 zF$Z#N*IOE4;$OIH&h+MbUD?qdHu)jPd_=e?a81kn$ATPq`E`pw2gyyCQr1=5T4UfSCJu)ASprEz^|S_O7H=Ff1LKJ^$x&vHf$oj*hc6 z^YmPo^BhJ{?i&lfT`r4nmn%dppXz@uSKLUx&GqN7RGxX8wZ<576Qif97|USy&(@Xv z_5%?msgEjRPY>}i(2^f?WOha0B6(Eek! zK~#ff|5kOJ@|%_=lPYH@J@jDw&=AKsq?3)}!0~0I)cXBwn5aAXb}iwGAtjj7-Q4ih z$A!niAiE4UnN-5^Kb1@6KPs0{!LjkytNVbLAg;e@GN&N~t+Q^*_=sx{FWmn}<%$65 z_>ankMgL!wtMmV=Tt8vjggD3);GhpDU}-ZB{HJSwJIj>St!7DzXjwoubzJjQ(iUsP zl?g;9nK`s@XD`+Y92Te_q0NIDf~8(EM=K-u^0xnRUsXVSl0dj9u|u&~vaZ%|g!bbT zryI(yYT;~i)*3{_Pal3e@W_(P)GT6_f0nQ*lW^0HAiu1F;lvb?ND>MQ(pH2@g;3UV zDNv;%%QgBrZEAl>zTC*NBXGq@Mua>1(PGr@Ds`$yro=eLRoFk&4i^SS#&Eid`GFGc z3A;w=!BUawaJ*yoQ^!)-xuZ3&i8Pqs;XHX!Mg9iaL3trnX|S({>7U9qQLkW6F0|@r zUPc4PA1tF{Y9`A#yij#*Zy94NuE=46-*)kYTTjI`dN#S-8daxyAykpQ!xWh8WCx=TF~v7lxks0Sf*h8|X6U*>-8VHPH&1AFCl8A( zHbqRDM^P_GMzV7Nl%)T z1IMp2<32@W4`)#7?B`$20Xl^^!Px&}xn!7pkb||#Z-#}cp%n(N!i%-F6DC8(#^=#>g4pYdwRROJl?O@;u!l!%pG9lY9uNPA);9= zxyo~=|=+bbo*hGB-O2M zWL)`}I2w?vy@wBhLy1imQw~IjAD2r4+oP)rNft`eVl2xR2FzDZKeG56 z9*2q6(^nWM-31-cG@4V%oLn9FKmJzp3joRE!KwF>4S<5F2|kECN9EJsvD3LDzwgq0 zjrw3f;=unh0Jq3281bzy08)f37|~M1QJrf~6N`utP4)`R zAYS^CKE27XXA$Deps#&Lb}(>!uGzSM9>!dEfP!8+W==am;-y4VVVZSXOE(L+UHsk^ zG0b>OYUDh$A}*u6Uy?|5n9ZPYM}|9Jm`a@#gz0{%yq%*gU%Hu3+jThxzLa%u6Hhp9 z<(tduIoLn^r*bvd{ZqL@tUnEXu+H`0fvr9_bK|lUY8e|1UfxCJh?7l_{;6E3pbd%# zuu6$cCh!C$Xu+Zd!3Bl}82c@8GuRhA7B`^te)UF2TAv9#OU~m;*R@M_&>D$4g_x?{9Zo7ocO^Ub@b?AmQ3OT1x?NRmZx$T;xYI%8 z8^y}HGgt`Mqxaez4mfdSVO)P0p$f7u;-Md(#n?ifGZI7NUB;l5wyH2>H zrmyAKk6{Rcr&`u${pNaCobir_?z2=)`5? zYL3~cQMY0Xj5LxP_1a$lF>ZoXafRTbcurY!B*4~6k~f>95#l{jW4un#G(KY`BcK~B zKS5$0?w2P3E@95UJF^B~SOoeX%LR5L`b1!?K9u06a-t*C8R3<`M-cfRmJ5AGUp6t$ zME~KN-q%e9c^9rusrLjL(QObZ@I&Wd;roN8nJLdJ!f z*XELe9{M~6L_>+;U`{T*_9%jJNjyJd;yz-SFv6@a42mJ6Zo&z4fZpl~4y^qC8st9g zWl!vog6<#fpI(OD4;0r~<+kU!6RX%#(mzD93U#q`w}m;c7HbDy_p4AHTr^rCfK>rb zCrq~Wa0Aq}ZY{~g9eK)tQWXLT$Nd-R*$z2@0&Unjb{)`#5a!@x7SyS~8!-D?2`R_9 zSw^}TI*nE>uLOVR@gES7DgW(W@F4FWN!ncM40wm(5Oupl+~Z`_vB2}$q7p-i{@U~f zVSfITV0jwNW2IBPaf`gb27r`D5zGAl1L?U@=1CzaE(~s$+7-XL{2ZX3N zj5tn9(Y&=95u!_1yd+vgf7js+N1ZZ#3Zpa zyxI=f$R)H?Y{L3~S)`2-cFT()DOYJsKC1$uwiXpWeA{7iXqS^N_CavMm@S0o>;6%| z80l>KhdrhRtUoxQxs&w=YzJ|nRG2EQ>-jcUtPxT4~?4nEY28+hVmloQI> zIcr>D+KGyDn~`CPp%TYZjz>(ph=z475F<(2B^+vm$uUWWS#N z3tP5|8Xwo?fkEA+y|sonR-2sR?AP!mp=2``KdBi*j&UiL^)JeyL*+Tu7-jj%G9C*; zrC|P6ta_L;Sf2{I6F6-R@68LX0WmEu9F8@%sVVwQfHBkVoC+`MNY}`8Ym7$KQSab} z6>^syV>lm{j(GgV>=i6A)46%0E}6Q)5IIa?45xBa|ZpE>(FN>u?>0b=R(>y z&c))w+pY)55WzT`vNgjFCJm;#Yi0bd~R0b)}jz>k*$A>I)*Z1x^#7 zn$K6v3i~I80)wQxhQ1wP7TkS_`V0B2nsaM8e|@#`yt%6Pq5gS2H#>2!MHUAxtch%Q zfpn@XcizH0EUb_Q|49jKa7nUyB3_;Z-;8P))0*p1>5nS4miCLfZlL`^YYRPJjoUaxd#T;QjQ8KCJs4zYx4ppgP1A6@Iu z8s!LG4Hms}i?N>1L!Ib?>xjI2YPX?#3Os{Ih(@$B$Ag zHtq+q%zbTm-s;Z`l`Lx{EHDkovxbiCj(YZZC68&l&3Vr(Y^b^St6*vqjtY+CqH^iU z(&FZ-h=;HgUjyD4VCiUFQ*61h3`}B%*Bu91$32I1klYV+lBg&qOp+nNK#v`gTudBv z;cGC-i*gV|!oYzx$`s;bdT|GNkn3{wUqk1Mymco{As$x0h=kTQ3XLvMSf9z!sB!l* z7F=67m*fyXEl2P}c89hgFFJsP`@T|vU;N_pj0$RD0b>H7+b8KPGfGgAtnTP~Q)ZI_ zz7?`2^x(fK=(q|m(UqC>eue&Do@;xK_y>v%uaX`+QH}(LWH~?nF?%5trSK{3uS#ig za+?QFJGbV-%mG#-R@z-l0isaaXzaHm>-mqF`yMuK>(!1jG+PIkCcEu=DkV4wZO zYg2atE*|?DXU45}`-x>5b5_Tg;e;t}B6Wx6FFlW?W9AS&)(-D3JISD=1VoOuiWLW@ zcrLwFw}Nr{(;(7}^gMqF1*j_uYa8u&^v@NJG==Kfl@6CBQ%fFJ{)mnYt3pMw%8IRS zr{AMxa{%c;ft6iA2?l7XK2tr!Q)AuKmG)@DOKo@J;pf4p?e$UHGcv%LNUk6CuCLJC z!Uy*Sf(I}rG&7rkZ%}Y;-Z*eDYzzgbjwek#c~*gPr6H8p{%d979{$6du89rJ+u>Y` zfT+L)^WI&ez|B$|Sz2C~Lg$cP*>=EKN)^PaE@{^p9tC`?Kkd`SeFAZK|LH=LtT!=F zEd>p%A+tk2nDrQm)z|>u`Il!ub>s^!O2Dy!?ZiNsj#&GY9T-QA0q=<_8+9N(MNb=s z=c*O0oIkx%3ys5uGL4R^Zu8i*mn4xTr^SccAy&q%ADp>hu-F)Nq_yR!0&hBOe)X`^ zNG1)YnEeo#ZrozYeEUcMX@AhCr?f3$UzE*+hGf~j?xN9F^4)d;I9Iq+PtsjltU0zA zRQ8+|yQZ?Mi~)7=7!yywsUm+Ik%p2aPslk{p_{(V%vMu z5r6@{=6c#NWf;KAeV+W<`*9i$u-#k#=^8sCedJ9@`mp!n?kn8O0TuH8PBuCld$!;D zaI|-HqvtdW3fFbmO;Qc3SnmQt$SOhmDK( zd!-i{Dt83{oZ-WIYI^^_oVB^#pEA*l|oY}5zswE3A)MlIixfXc`^a>qkw zsPQCHHB0l88deoXGbj!}`*FPg>r44Fr-9<eFFjP zTSsXs1x$g$5NLZg{T#Tqm+xCZny3ohE>FRiVk(Kw?bUjcS8wEr3v(yrLn~xz{LY)x%i@Rd;|W+ws1+ z`4=+>4YQf$DiE24Jpt+U9jEls!EdhIioua6|0T(PQV zz;zZ=F*zwWqnj%=G7DfM_!o}Tsnp_|soL!()kI2YSLdv>S86!P0C~Wk)gkBAqR0zX zF+Y)+8#*8td1Jv?n?z{W&K#G5Y$%vQ5oa#RBi0oWsOa^vTgT)+Qf?GtS_;8H5Sn33 z8i$^-<16GiL*ENPYUfA}DV3Z5%HbA(GtnQ+Bh1{HO}tQxajCSOM_R#uh#G6AOEVKoLcwSEUjWbLcT@I`3Z;y2#K!0`ZH|w zcF3pF_{Fpoy56&?e$wG^b&Bb>A)=0skb5aB$wsUUdO8VEZV3jGLx$dZz`EhgWjwsq z{PeWT6avq1(Qw18qos2Jj*s@1E6HEUw+J9K1>8fjc{gCNof|h+<4*j>0n}e}QOP67 z;n8}&FiovSSwqfA39fW>#-0TV$ml{G9KRo(g`vWLFCvkk zV?`aCrRT_ZjD4KR*4w{Cvk{nF>0&#?1_27SDv?7B3-T2<`s<`1q*b3 zfr|h|sTT)%jNxVGW(cgrq;o!#!-Q3Kq-aIEh3NBYjl6Eyky2<3d=Sh8=wqY|cY?eU z&5Bd&s&(P!rBle97`kp^hTeilujpbN2r9_1&bI_Xt3QgjrJ2U4EO<1_1QhK|WV z8Ddn%)4{$Xd<-dcDi)IN4*XSp5Ms`jvHY3g{BwnTKDvKCFE4DIzD6B2dX#!mWk8^1 zNeTs##Skc0R-G``w-K}|;@E_=n8fp?(SwLVDnBMmVYsvOVKDhe@JX@-!5PcbvkG4U z=$k;PT|+X24u=W{Su69zw2}UzLP64W!qTLzG5k?T8JQBs51fl@xnXb*RFaTgIWw0* zVV~p%>H~sv56~xhg!11PP7?bIcrg%Bb=;6RQw21AkQv5zTd$g8Fm>Iw@E<$(wjV;h zt91HoHKoBCYj}5=SLwpvDqmEsN>v9di-n3TlLJ zFi3G0nEkH0)rIQF-zGV)b1O$&mDZ*((1F`NXI` z>cwsMh}t{y_US`5*6yM1QnHTi2<)%GIWv~3eW>pJi|zI~bCRCcLo~wz{ruy8cYIU0;5rQ=Kl3&u zBx{>sgp>H|WZI3BBlBzs%*d>z5INF33L_ShIQbpjyBsq*#|j(5{L>Tsl@Rl6r4>2l zy&WV(UE~xTa-AfjT~$SAs@JR*+bK$z;Yn2o-Q$IvE<0$ubBmnpg{Y@n%wuFe<3!UH zQQ4-8D_Nr*7x{|ZWjP|T%u=i~SJH>z%`<3?#{0^PH!S9qHy~iqQ|j9k`l>dXAQ5?s zIH1_W+gi<^ogi)8ozH;(prO2xV|2JZRcPx*Sz2#W$^M8B@x}H;a!hR(wcSi<)j;KF zwGpKbsxIA{i*J!s7|7yH+FICbEW zMebZIe#!;6u(_5L`BcmyX7tzf!Dl3CxZ;o zB17YtiE-~L5nOdn$Y9V<;xIn`-B|L!p#$X~dCrN4VLfJx0&V=Mp;Y}-*xETe=93gU zFH5d4i(TPabUw}L&cWIh^Lh(5Pu*+)=E8iy#kiQ6z@2&3wF4xZHT0sP`CV?*+Cn?bpSvgmVN=~ar_YvXMlcEwo0RbPlpqOd49oR z11@JeC|2BTl{_4u?B#nrcmvKsdFfqnFyS_-YzLvf2XJsy>;bO$UVUv&6!b+{;KxFk z=f-{)|H{7!pSgpYO#)u({Q{@eu+B0nii5#z%uvIG*}tOF?~lje=5F{NIh}6|FPZ-? z#gp16g|hLfs&9a9hmho%r})@VN^t)}Gju`KJt$85rad8)$&b~UhBi`FR9JVPuWpzE zG9^L0x2x&i@%Q6u+)>jZU*rAjpg01zEYn2NuhlT6wh#2W^(zzseY?pBL~0dqfBFq6 zIJtcs0b1iv>sJ8J;sm+ySbGdg`3x*XYI7v9ag<`6z7Rt{FRMwg1{~;MT28AYY8X`6 z4iB}oy*|W0V4QmHbpNgvDbQ;ee+GK77yqf4@td6S6@wr54FHRVw%Chgx!4E-z(PZEoMb zh#>3m1vtybP~G@?%5)xpf5#7Uv9DAgd}rZvKYH2j+OU&K%IgNU;7vMu>tqDP%$8K2 zych1n>_7Vx_IECdl~8`SJV$*b#{ZC^Vj0t?fP?c(tWRsrxCx$|wOgLTsa6bpCQs zPQ~i{u?WiI2-U#m6GiGl7z~>&kz}P_YR@)NNJy;xaIMe+cv7xuX2^+`5=*(b=%FIu z3Qv{T1c@V6D>gnB$Qg5(%M6X%PM9mVNq8Zkh2^14tB+2~dW+aZ%@wSDy$KlbzG551 zv{;9PQ^W;Pds=Rfav5a?Da0kpYPdn&Dn1YknV`-3LR^-wg<=PxEW#ZE)n+eVFK1f( zP`TXHv7ha|re+pV(EcUVycM|fB`Enjus*G8sj839g>>%}?9{<-8^a9!0do&%e4ffN z6mQ#$84IR0QhVVKD-(qC9;7uUX1FHPu- zs`El4ce(3Y=2R224m&l}z+U=!+?4*FkB-wPl}V3GnX9O!aDvmOuxyflWf^KQs#Hy{ zX=ik`vU_-XJ$!E)OuF7y;&d_ioD_gIip`ZDOoyL6*?62RE|U&n>3Fb{r;t{bE*N^% zca9_tBQ3jNukD2*R5QJv&Of$08zU=Q(QLm?S3902nx(JCdQG@Zqx&;d&E-hi%%|DE z99(WcGbbB2fVAobN~W%7W$9*UYj(O{UoRe)V^8V+N?l)U&souBl6XRs7}t`^l;fzU z|GD<}6)UajKr6MZ9O87`Q|hRw%U->US=q%bOMJ5iQQv~5rk~5mC#35DP~_2orOM+& zzgp50`U&F_)}VWZ2+E)~@5dJrqp9S{JEAoCekNP?1qlv=i|of!I>*66KX!ycQ2qWa zho9HIX$<&+z*yyp`;od0c$9^cdduAz-(UO$h~gF(e)r_5*mIq+fNPU^6~(3f`~dyY zVh->$%v@HCQl9)$a{c_H?)=$FI05aYxBlkq)1sb_01tBZi5KeuAW{zu7Y5w$U6#LnbSv;)Te^T8y8z;|G@Ku7`_!z|rlZ1Q zVtNSIY-E)nINKc^I0qpzN;XIFn#dU6llnq|(4a#5e#)LZdh|bVuVo&{`dldzq*>yk zE!2l5&sOB8sBui0jfysxL9A{#vIM29%9M@K;sP6K2~}Ki^u&J(wl|B=3Lr@8_>EQy z`A!B_et0(@O&ZjH;A9r|cT->KBWlD6&Vm$)MnWS&B^e=vN=qbov|=yy$H0!coZ;`o zp3lvJb9L_It#twAJRPTS$sjEAOu&#QW`wy&h@vD!31(F2QH!?2)u2J4MNW)}gIEdk z%9!KA7P3#A5*sSt2ww<(?1;zx4cZN;t&LHoFbQ+u5wU{F@Qc&?=qAz!F~|_TMywe8 zO7NX#J^>nF9nK2bCWvOJ!9zLv9l^j**oMp=j))1`7nf_P<`dp%P_8g#9L`^1z zf?nqOLWr0@lL?7bmY6?qM-+NN*>f?&T}fvVY8HXQpcUn*L^T^DKR(eZ4lc zNFljKZfN=_}& zxr!d1(qxN4DAabQ-Wi6Im%IXk7A1J;t}pI0SO-TEc)8n}iq3Jp2Di+D(g5>^_m`t(Xe&PCu@6fAtd}~&!5~XXb0Vn2;aDb_*D7{e3p}XsmDJz-l z(Kfg7QH+}9HQvQqJlAy%72ZehSLqGf$KBP`FiE@8E$kQ$hS$d|KSZ)G`v7-Pciq%0JR=HJQMRtVaEp4jdBov;UK))&T1E-&esCq&L&I^0=;#p~NfQ_2%cZOO*`ScQfXGBhucYYT znDxMBngan#_?S=?4TVa{ek>vEz>+G#{p7h&wE&`BI-NK8XokRLbItYhF>l2tdNZx@ z*Mg7$JX8iL)w?@hsw3X`MyFtS1j3bHRZy7>ztD|A<#gwOb=jcPZh%xZrxj~#Y z8kl7#*XJ;juwYK`He=`j&}kQt$E7cd0k{>GCi^^I8RCHsQqp6RL}7gB5BC8i!P;$h zLt~)h_YCb9OfVWr#F88ar~G>Es9e0achE=&SgO+rVsyPI;8eEHzgd zi!W&=V^BD$9cNMSQ$$BJob}m@arz}O!(>Ui7crd<;eF{>U*i1G|L;$C#jHToNKk`9 zLK=?`_;-FGNPMl7Mtm&Z@&;Y$qI_tcyNgfn?2nOajMvLUvHQno>sJuIOE=n|yG#ef z_ZC{2n1GKZ)BN6p#)l6)VNVVu_f_@98tL7V7~?P9(060N_2B7$^Lkm)!(01L64!e- zXD_egY`a&B`o9_!7HwyLR6aq;hrb=8JQM#6h(1$>oGP8I55lRtlSqooig_<0g1KN< z5DVrMFnV1Lm}6GSDV4K2B#`_2IJ+$3jz%$Z3^9q`zwqeWrmF!M4V}$>_zt__nt!Gq zDI5J@aX3d(dKvmYxc4CEnpbKCus`m@@g;P9vo{WKB$@?(_FYA+lq+$pCJ2FSp(Wy1 zYF9}QPz{uH=k=JrZ^b~O9_Ok3Q2P+!d7K$5dg0bR4j((4w~_Pbq|P`{&0S)T}_d zXrjEBc4W{(k^(gu;&*XTivJGwwQ|&c5N{ABF+55k78es4b9ySQiW$0vXR_o}BsBL( z*gY@C!qk0Uvm-B2YkZpDw=CYGIq5Q5hvP&dI*oi>wy8q#wv!Sgmo>7H#ee*ZQz@)$ zM)_C9FJsp$Pk#X)CFl`(jQnSb(^pnX$jtorf(pi&T)WG>vqLP3kJZ-Tzz8rtO0~B9v!zEi~ zaQ>}JN57Y)`{PJot0p;QJY9oOsAv0pkK8;fi@*T6BiV~us#nkMTiqCV&u+<&)Y6yS zO!pz`fO}9R_jQ-CsdiI({CFPb;2S35W2k)?RM2gdcSD~^mP+X zVo>%=@NORV2k!eDXj7nacCiga9@9yq1#nM!a#eSb5x$2Q%05Mc^kfbEsdc{7H(ph_ z$Ok~;AupPvurfEDsvD2*M>U#j&yfsc=N7AS`{a8*YEGnfi`B#zofv=RP@F>}-mFfP zm8_MH#g)sux-jB*FY+?Zn5U0cBbv7M)+~!MIfGA;c)U#>l)t<53}m~LloB@o4&!JV zs65r}MlgnX>k>t-#iFDSjhh-FEpDTvK!P431(|2IEMR;oQKJY3ATIeFek7mRcmHZ^_~3!_llngQp~)|^q3@w`&j2jIt&th=PriZ%_7{DoF0Fz z@%oNeo2m&S_B%4n@aeMZDw0K!N#a7%iY?8|h;{BitTImSS3u6SguhlOhM6y^c>_{3 z6^hOb?ARab>t1lr&ma4bWWyZ8=e+KeH|y0{sc$Alhd!(UuDK*^vZQ@I;&&ZkdYRz| zt#88LqsK6uGSRWHvcW!BP~M9TA?PyUrY7>Bc z#diyk;SPrMfzT1Kx7sTrqm~7_>)Y4|=SGMhQ%9VF`u-SJPrf9*uif}cGb=d%+yO2y z^!GqjMrdcLBUg}fZ^n1Z>~0i~xp0v@rg)BR(jZdylHDd1F@t?2fb5X?zo_8AKJ|yI z(6>ipkGFbpXuXCIi(X8iAtx5}68$D`x>q{rsM4%b4{qEoz=_t*)OtM)I|J8<=u zFHe;B-ol;RM8K(N4vn#Tp!f*)s@Vu8ySf-CIO7@#lFy_~nqd5@=mTNw4~j9PEc}|_ z0m9SuW`OA$B_L^*XSEllqqb?dC6~>AkVX?Q+8wy?z2<#50<@=#4FkS__%-JY&S~JS zsiRFje?|Nz71B$!AlAxm0ig(o>*ONj9XLt@J?WH9yx0B1Y$I!`N0K!#r(dn8Od{f4 z4a-6|aUgm`1K4qD+Ii%&R09~M98rpk@xZH<0RG@4J@S!3bRU*J_J*Gxj&_@dX#@-Q zJaJB`@lGP5MavT93^VvspwT+CK3m!T>vdDs`*|p&hpNDA5wmFBt&Kb*Gu1Ep6Myxc zc-E{>3mwDO{QvNFPr;E#UBl>OV`5Eg+nm_8&56y9lSyV`+qP}nwr#6Vp67kP`s&oV zKR5r&uIk<0yZ72_t>2P$cGjbS57ykwbMRGXK&aTol>v9{v`%XaczHqT^8wln-Lt^S zM}o=B@~FBGX?)3_wuQr9$H9^K7uUM!@Lr7HCxlZ#L!>+$4{BjY;wbm^+UB>NCd z0TYYrwLWylfX~R^leu1ZchP{`Bj6vvJ{IrGp6-O~^5CS9YkmTTUk7|S-%B}!R6cG+=6(omqR}(IDtna^~8xTL1?lcJVND^AmWh7H+SHw)u z!hR+&J9OS9q`l3)itJ5|SxAT2e)GSm8!7H!!97yP6zN6o6j;_1)7g&`2nJ^~Oi*#5 zgqQ$>iandSo4*Jb3J6(=tpuzBp1YVxlKm%==k8-2?|-6!g<0%302lpcVG*~*Pl&>malRMThN-#YMl;N64z z$|(Qg+yHSGT_cm%jmRaoJLSSXg2hQkZ`~rxshpg2?UQ*Ki)32bWk=PCo0gT6n%dU6 zIMM^vnD-6TAF0`4_dq6;$OJ*#hi>S@_w3_oG}LXiTtP@Yojx<_eCj?+0%8a zXPbmgmh{Dbn@L!&k1ws4tK&Pq44??QI>vOnAF^g25IKu5>DE92DJuJ>o8yki;6^@- zWZH5Eiq)00?bwGeD%GHcO4VyC1MO;PM*a6<2{rue`Y(1O72^F}QWh$*n?xGzm?%>a z{84VG5Y&qDB?j@()_)MBnMkYRjVw@r&0B3I`r-{nrO3|b3B12r0y7bKh8KweF{I%^ zl?xL;m@Srr|0$#8N;oCMAO!?l3Ez2+wOKYsp}FIe@3!7_09Y_05-GTMrTB(Nq-H>F zPR3m6SV58o8I@R;cH4gZ#z?d6PwOd0T3xyf4J1;Hmq25&?3$pL&F^Mi8QhU*>t-Xy zcNgWU3&XaP7QJdP&$6jyzO9XivcSH?dH9lIF6|<(3Pw&0E0wJ$^`` z{v`BhVp-_Mk01nuIIj*E+(E=k+2ZPKVQ%i96%AV)P>7Vh39fKp7>;&~o@ zCg*<;x77cGxT(b_;C*JU`D&=A3mGvZV>}^bf)b&ukdK-1nk-h^Ta9Y$l`Z~k4ebE*DP91Li=2HbyXj}d5XZ>15joh%L zwwOsA>zQ*{Jx&F=5;7+VCqGz={KTPypJ`uin8O2#E95WcXrtyK+#=*A`zB-+&2GG7 zlEO)&G&P1s!|e1O!7(-e_Gx`6UG1CA`hqf{9p|LS9g_@G{~3QPZtvShY&si!gdv4Z zQde&6ebj0-Gv0@c&(FNV^Qx%HzKtpDjOI&&2Ku?3u5!vIu{XLlQXiShYBcVT2kTA9 zw9Oh$CMt31GCHOS0#(lyEur@YBzd=F1`c4lPG7uyUiwkM*N>Lx0^sI|N)yo4M2dJ0 zD)okI!6;{H(KJ4LwIjqRxd<^8S0-L3h*bY<(`vStEO(v?=iQS-1}v@K{UdBS8Tj{Z z^zb)Zgun_tXbu^sr>`M*zSd6@Wk8rqFik;zy4U0pzAI7C;%bW+x1I_|OtL((uZHM6 zU?JR-Js&W6H1xTIZ%KoKe(PII(=R`G{&v1@4Pk9 zsZ|SDvR8XHl-uN)PcYB6ej9Gf6W@m0bH;xRx6FJu+wSd*Z^MniaVsrJT4eeBzlK}p ze+)O3{}^ry|1sPiM*$j0Od3l65!_r|bR&SyE9=+%s{p$Lr45NJ^;=^(1tSkbr>}qSO48!xO=IZ8N;~X@shi}ltXrfnhT9^l*J`T z!=?+jY+B$!Gl{8UO3a5sw*;!mr5ICyh!KfUZzJ9s9u0Wc9k(#j8j;+>0h4-2F zKn*y^`}bCQH)7TAiU*plMtbS~15%+by6HT2I-_Ji=4#vgwtN=yvCkv5RaOM?!BeSL z@~U8iRsyC;jl_lJTmd`Ie=*`)73wwf4(}oHpZZJ|9SxtcWtF|P$k$^L{}I}_E#BqT z)749Bb==A$BT4mI3|qJ18mL;084G@oq4hd>_X;Z$&@{_^o0gZ_6^iLNtD-n$Y;yH; zz4U5F)Q}nNGi)W7d3%UAwn_+&N7ZdZXB4PyMm7}_>iussmbBJ$TX%|+O6LJ`o|-uG z!zS?0kAKy0w$FyzWTqc-GFm;1^hazMHj<9yHh;UaYT#B#%ZxW_6mih|yxqfl$YimP z0H`Flw}Iz3H5!9}RX_x=J=Q|(Uo9B7z2|4X)IMwXo6_WO*US9&2M-N_sUO?tL&aPt zm-gP)-s+vFrR}0x4zv4Z1_ZZR!)$(|_|fwjWqEB6w^_uVv`M)%cPrkq5CSq4747rpuq>>OH5CdqG5Fh~fW7Xv_Yu&?b%&DS{w?DKSrF zL7c#uYdaO^`hSHsEJ}L6tN%N`6Jkc<6hM*eyDP!a=*t|JFfr# zz^WDPsT-6+BI?K_P!anHhh*vwiqujX!jV5m>J<*&=WQh5I-JOY`OrsI(LTBWp~&@n zfxxX>C1GU$5J)r!$S8491H5$Rqg0I-dW%n1a(wSYJ>u*p4((0cg151l7BIf08$IW} zu}V}+gG2(=k`G9X19@9Wa!i#5*z&om%Mo9VU-YEP=RLV{qsa-q`F!)ONwq0(4f)cU z#$*g;dz8b%>97AhijMJv?%}gLut2bPo1RH8hP_gN^TbLdPU8Jfrg?M*cplB;QVZLd zd?Y4Tvf$!8z)j-J@+slc^U;GdXYVD4uYF=x%%bN%z!redcgj_eo6qYGxHfWMO8_*G zKPyaI-~gGidlN4i7tS@SRD}K8&2gzL5=?R+HQSa``xJ^vH~w_1fP%8KdoDOhk|p-q zfj6KE!xdBM2J8mt{sWR3@K*v6`Pk0|4~b{v--M^AFW%`>gveD$DN8W73(W21Uy00X zT0jw>q{ekV4{w7SD}d=#<|ddNr~b*Sz>JK9TY&u2e`1b%s>b43kn?pt2c9{a>2=tk zoA@V?{3#mM@KyB3OhaO_Xx2FP9Q!!FCe1UDumW|DagJ$o$JNh9-E3b9&XEv!Q+H9F zy*OU9W`EA)_=PS1Bt~=%%Snx-M~+7GUvcVCorfz_q1FkoVAB&JPcd+n4#twK!O@uW z*U|@FaBVF*qu@P*%e}zYu-Clv?!vq6StahT;rq{g%2#_*h0G61$_D&h;hlGJD3VC4 zBmApn=rO0m2;9TwHcVenmUW)&?>MSA5GM7LRT z6mwk#FnakE7}wjgL^0c;k4hRe!gZw`7R@x}0dUzMgjFJ-W`Lnp|KNT{+e8ZGVFvA-fgVbo( zlVn>)i&^(6WaL_9I_DT(&e={W%2Qn9%dFgAM{0aX*0S)ePq6j&HHb~P`54Gs6Yb_| zItpC0nDv>ih2I{=J*SAZ8KDZkELsyP4wA&TIoWN&Ve19&O!ic#dz7aW!{Q z&WfB(W&e5c#=6bSdzHOW7#gd*uXTaZM(Dsv@6!^s4F4Ym?6i>r8Wht0Zuus)>uX+h z{+2hxyI6VGT+w^Ai~9^g)6O~5hCnfSx5tdS&T)D4n(CbGN-(X4j`yW#8-gg7c5#A( zfbS4)IC}=rnMeNur0L)T;GjGN1P0#M(Uq^?Z3UOT{CHcJ zPo8b1KPNi7GToXUUz?oO&8rOphnwejr>D2uc^Vp7t^47Qx2FEp?AbK}?!SIGeGQ?=+5(s&?ExFJ;Q^;3 z>VTBG0>Eh|8k8Og_aak8pNBwLVnJ@e-^s30oKRaIjv2xa?Dv$uWZkFC7HqcW)DT^{ zGQEh3EXD6P0%vM@6z<-mRI0fo-?QtHo>T;$6M!GEk;SuIyEr=f!*}-vt6%3O?l0e; zL##z)N1^9b!A_!cAZtYWvje6PSwI5Rvdcv9we4;wg}K#Oz3vZYBS!>f!qhpw6wy)5 zF?i<5d^~aGG=+?3HrP)3xEf}=o^`7s@mXlhJfR1Go6nv27ztlMMxB)CT`re&%Jr+D zuD;$8pUD=cCuo7BpQj`BYvj#`W5RVWu=X`e@WZ_c8o10zvCsc1_^Gl%=G~M-j96ts zjU&d4w#90&QMAPhkgV>s@DoS`+|%KD|8H#x-5%?&|4(tr-Ty5vLG>8tUj`yubZ2z> z+&^9H&1HvR7242=obY(d-$#B7PdMq&zq7OvHUEq2@leNV}dYQ&m>zK=0PuF+>liepLGQ zTP+Ho>Gd@dq_?7HyFLhK@qq{8cx&4%SjMGOG&a=Q-ETTQGOxIj+uG9kKpS?th ze9^6bRUz()*{V95lgsNIUafWQGGdQy+`YCw{}+<3E!NroM7hdoakLiwjvD8?a1fbK zEFRo6GCYG!E0G{-jpA>Ym zz+;7RtUt7K%E?=-;4;NS+>#|M9j8@&%v{dWix5^JTh&?K&eKh9?r$+&UZL9x0?0mV^y!`6I> zc67=}cm+lbsRSZ)I^k|=k;zgnbM~Om+x)MWS>tIQoyp)xKBLy3dFIA(fAmfABq&LX ztGW&nt6K%wE&qYc^}C@Ce%s`w>#>{XoYy1k&(|ZT=LVyU#f;n8IC&)W;bW|9><(da z9FU9vI91U#MI|Nwi868j#C5NZpGcO- z-x0k%LDv6vH4Qz;*a*r(z}ZgH3d#<^OWvKFZ!M68kX65&J8v;u!1$W42V13R`M4?C zqVLrWEHx;IsUGMrs z*><@W_6k7;3%l&SfYeG@>Is2czUToPY)bWGsNWBXI+M*91*?P?&!1j^o84D*bWl4K zoi!4uqN@BiDpnW8@;|h&>==Crf&RkE40##j#(Ab0%+%3Q`3L=5-`y2$&A+*JKicqW z=m_gY;f`E3C^`ANkDm)NSR(hE`Jw_nvooT<^R2c+5He1Wu>I{30Nb@7BqVRI@~GN6MqASz51ds^Ycq-Va?a zyurozuxNIBENdDuwHeP|K@uyIvLa|D9A+w{tO^a4{v`Ifog*d?C!RG?dt%|RUNM5p z9Y66lXw~VCl99RRIPw+rHh!e1$>SFK^*OV^csfk72=0N~za#S8S8EQoVTgdTueBd-LR~cu3@0B$`N+ zyMatrcSCAk1hzdcY&M^vvb#xtR8(0NjXBjPRq=@EZ?!_gxoIHMSm-hf($ZLtRI4Y; z+Iyh485f2UADvOaTKznG+A`>XNDEyr3X%OqTkr0w%DOS`V1u7VtIyUrFwMiXPC9F2 zPH~JDcR}+{Q*cq;W}9i(`b&*i@1QBv4v6656}>v!UmwGRI}D(=DNsWr03=q-{e5$- zOTcyJsiN$!4oP7C+8aojzopFYGjkQ>c>NCivRsmD$xK&uXl;-??qkvRRrP9Qt+Y*A z$i-Ypm<-I)m)#Ay$h7r`GP5ZsC=XCP)Js|2c9fsZQh)m#pYJo(Ev|i!7?>$j<6c`^ z-!G9U6Uu@A-io|xK%JGDxg)t-BcZt;VC!x@`)mAp6P!^GbC{|&cJinRRz9rNmV@EE zCreca3PXj;-?!?|l*=Ih;5JD9p|BXA=l;ZHV@MP8Ly==rcUYC5mlV4_k5A9~&i@!? zqxaguY2=D;F5z;NgS-Si2ycv9mj~$#v(tgbX;m;*4VN~wib;dJW*>y61uqwd&rP-E z^V-@%OrU>yCAu-kOy_J z;>u>6`)fL&I{Q`j8qBsV`&Z^^Tr`X%ts0_J)_XQHCKa*5}rPgj67wAot~F zN4Vf6{gKO>_Y)5zjKu{pC3H<0M0G{gHS~yVpO2Ec-N>Gm>V&YXzziaa5tPqXr#k+QXxoV(#(SLK5?PxnoI5QCJ z3vX|cG|uNrYz(Cku@9bQH>G~kI{kTnR;@=u$L=ck$OSA=$5HI4ip&~+G_V19Rc|~h&uQH!iJx2h?0_Gn!BWNOoz(n%;5gi9yKRA zwb`;j!H3aRz^bl5@xb;0O8^baAr1WkFY$Kx%?YRf&;~L(7>Tu6&I_8rQ@?KcX4t*DULWo1oQ8z#)>O?WGp6b`n9wj4k8y9HJTM?f5h4YsArka()+i)kB76v*U0+iWD5A^>G8?g zQq*7otQv31QF9i4L`fLdyR!21>brV2H1J!xC$rhfkGtdFhl_J)&@Cg`NYTtHBl{8N z$X>uUb`Ym@$wq_Sxu$D?#-$!*i4LDn!$GbHic`s4LsI&a6#l@_U;c@SyFH^2mKfypc+ zOeq5*&Yxu|TvvLtxaoJ-Ke*t69A2|J4O zNW)4y)NTJDs%*uv8(2_g{fmf}e2a;l+vMqov6qr1nKl&;w z#|l1g-#da?sshP?GYwbXstGqWzofq&n3Bfv#^O`_his9Y7DPe6`)!BQ6UdX}EfcOs zV3P?q?kt5Zx&8%%Gy~ZFU?r}<9>G6_67?Y_A187(KQ)lq<2bez}u3KtX2JD%hMuu>NBoLFg6T5Q!lc#JEWIA?yvkUm##tn zSJV?g)mydvyb8MFcVT8+ZvE^1d#!JT9e<4z)+noIT$2P|3Jco}pjX8;aENJY(Wty) z#<1Z^Bh(&2yEF$zb~s&6$8S7!EPuD!Ho9>C!ayBgnz88N^x=ClaMZ!_SkLSe6Rbf#1wK;Wm^jHOhZd08OSyc{Q6=TY z>GV+2k}kTEyECrABV#^;@&aKarN3gpvpnQ|-2z#$xyyIQ|FtN`z#gVO zh^~FmoZKlG75Tt#Ud3o=;zsgWnV|*UJ_0_!9Ea(qO{h$L`i{F5R}5lQ~}X)EsfrWlW7@qpeFX`=CczjU6WYmjIBRspc+`P3ZWO|T05 zaJs>{E9G}L@c!z0l1JJ#;bp}R@7VNSr)_SY1gIKlmoC0-dY>nqY`%`@D1V&G72k(; zkbl3R77eI@wCI_ET;a~p-BiJXNo-DP2YI4kgdZ~wF}&0n94A=V#TY9@Ri;w%jKtI-@l6+ zVtkDKrdL7FwL~53cKA1!e^t;G%~dvcV@RSp$PWSCub;@ght&0ej6r>oop>OoDjq6g zQuN#RXTXAOwT{Fs^{bM>}8pOqj zo-$)VH~8u&C9m9*T+CEN1E#zA=K2F8P&h9KP0)eYln5pIc=28Oz3A3yw*7{=s;>lz zJd%Pyx7yX%#JVU&ctKvEQ_dQu%*$!=UWYC-8VP=8!S%dl0_(l1!h@O`V}ykF)9~8Y z#K{#h)ld7sD%=%0Ak}f1moB~eYD4hZoPW>2#lM&L?f8P47i?>wv#)%HTB13ox!}oS z|4+!4i%026xo-9?ed*UBN9~%*D+Vb(yjW|=*6UCX_g&J&`z8+j?TmMMj6Qe8tS2{J zN`TPM`Hym{ShbK@l*9M14&&3zH6J)Lm>b@t(qE^PN4WBBE`0K$!($d2cX<8_{g#Lk}cJW&|pr`&)%Y~R0N-hinx~HCD5Wpop zsC|_^+@=kB4zQtk@)+(!98i}062cNK!*+(D@<JgRtdk;zYKT?>6+Cyk@j` zy%V^h)Xv*n$)tF`$&#gJ^#mt>)dx3}$A4iN-9F==6m+cqM3aWLidgq%k zh9oU|aDu13Quc;J$i%oTJc?f2i+C#dEw5x~`Q zfaZ7g18n4vwiVqfeuOeH;qo&S($67x*bq@PrxVXR&hD_h#Nu58y}5wcONAHYJBboD z#Vi`k^v(Lr3BQ@`bzWyJY3TWw1%$j{*MJ7AqTb&)mW}8l*_MR`4y?^AhV*hszZql3 zn5hplhWW#?Y2*1eXkRfqtz^yg<$A)8(}nkjncd$MZ_-OBSLx|6A!CAu{@7f1A9T{s z9_%9M?G8QIP8$)6O+6}Sk|h|a@E|Ia6s9>xgU$Iw+Dsu_&Rz|QTd9m_4;T(^} z>rKPm$JXt9O9^{{@vJ4goJg1fcCG#}FF<8UfgfB{?{j`Vgix9@;H7ZKe9y*DQuSc@-bHVyHq7tGX-N=Y4%54uo7<*4Vfmu**eg<7Se&0Iw{&ab_bUQyVGOOChW>?(D^+qc0)a1ECVj(SJZXD|TE3kG!Fu+%s=pld_PcsGG$GGS z&P}m2Un7wkFEbMxtd;F|BYhnSw=eMy2 z*j6Zi5f)ex$?h#8t+6P=;U#AqMKGa#A!1bDS;#DmZNc-H<5p}_^!_rMK z;7)`9lhh)Xh(z|L&Gm&p^c4#nB7TnNJzEK?$|{Y5ax4TlFq0nQW{TyPpa7RS_YR0V zDKJUlc=;X*CZRg8p-+NX{sxWU7FExW*#9jJaI2VWz2g_yu-Rs*h@f$|#kEFYKWMxj zxwm2JGp0mA8d*{qO%i=cGb`@0W+!w@pkIwUzB{#bi`8*x4#CzapH7ycQ#JB5|y97#^6Sul3IfPx=In5;C ztqB$vW&{nq*sQTC?p|)u=DY-O&zUq=CtG0ZB%E5s@N9NZIgtYVn>(tSPWq_diSMYf zC#4HfQ~$)k?&Kxcsg_aCiqr5I``)FAvB;%{2M~bvLIL0iwL)9ilf?KRCJ0C)4G>dD z$P`i;W-q?Korh_cfXEe^6ijN*Li|sQUFukaSV04D-On%97ENh6F== zN~8T=fSyL)zolvYp5p@R_~Ojl(OJh5J-w%y88=1GY4ZKMA5$RY_p*FGr%vxl7u#zy zHolUtX#p|pk7>h3Oa5B}nFDt!GvhBDLB6_WAi3&h7_b)#!~UvM9@i+z-Ktqyu3TP_5l*%enX%V`SQ{^9chYLP&6elwt&ab z3ar|Zjx(fqVWys{E@u3V-9+iCKF=Sxjc|?^Ml3IN zyv`@Z7jw_&i0U)2Jk8<>POnK1TuMWHy zz+Lcc7T!HC-X7B(IC#LrB77MpgedQU|I{5z=c|uKr5O1Y2ymmI{4V)!=n&y~0)*{~ zK!)~Dw}!9keYbOzwwzEt{9>KDLO|=;eX#GE^JR$6*>~<~sm3?=8JkI0gcFp{#!IrE zd*6@V1~m79y(?J#?Xs|(m17{H+GPB~kQyxbR9FiTpfP-bnpC|3>7NGxGyh;OW1=!^ zS2ca4Ds)*MqxQJ@c))BTP%B6te>|$l5s?OBe*z9r$^9rHdst(5I&7xH(;Wr;ANo8P zTL%C?aRyhEq+7Y#UZn|N)$spm#Sw_nK%rtt8MTb)rBVDW*e>?M}Z}o6i zJ;jd;s`*v!6U@`yFS5~QtUVkS7B-0PW8YO@H&#K+$?mgy{+Na)AH0k^C;#!~eUHtB z293GyY%&|V=1{*mPDcO3r}6jj@3Bkn`;uxIM9YQZRvei@fJl&A%cQ_Rmb(0Ev$+Oy z{>9M3VulN9qcb*H=3Nm?x%^=6pq4ci?%>>Km`SdmT;nyaT_+#PW~84AXhl%F(^+QQ z{Q9rEkN2(DwvBxN2bW|`FyG<4XQ&r11&Y(GI9O+^kB>Xdzg^!_s0Sxl*%UKKUti;` zVdwb0NWCnUzYlKNJOk*?*uL85k!8~2+pVWwgVI7xY^h zpI}xr3cQ(f**lLxe`vyX=^&Eva%d2{2|g){=LM1>TS6m>F4W7?v&33PkXw_Z%nf+p zG_@#BfwLxWJGb%k@xAf;`_Pop*$9M!uQXqGy+J3v%aq97ULS}1jD!L{ACIHA{fzn0 z(NNJ)B0S+)KCh4Yl>N{OT@fq!jD&*W1a*{!YG%qfdUDnCv>eyUG|tjpJYQ!Xr+Ac! zoF5@hQ9O+nsd3`sEZpSF$H|2ju-Qz#4PB~EJ!SEAzsKDxl3>F9-B+o(aaq$+ZtWk# zdLOg6O^lTFFUFB$ItDC606^O&>~jqfRH3=?2CWEsEgoa(PG5&Ra^Z zM<7arFQYamW$E^f(fqu;ptnxxz1VTKcm2gmOPI(`b9lr?YjtT+ZOHBE^by!@Q9m`@ zw26LNbP+OFOtwqX?L2KkGqeIJ47Mi!C{mW^==g4?i0hv9y@FD=1N2=Y^Dm?MdlssS z{(gHjxb<8Ln#cVAjvtBJ@#PDz-94R$;m6klCnPMd*I`SuPtWz@-$O_3h3@dYJeN(o z9VLOQd~??V+LB+-G7o_6JJVft%<4y7_KXDcBt|nhYc9Y0UP<2+xmh);*yy48wFl?^ zcmj13dcl{46pVJ&)IzLht6VKj%a6xp1HrGe@?Rg}zMn5IHkiJXT|N^8zHfeeIA5H6j6X5?t$5ZO}N^&$}=46Mm^8*YPi$7UrI60m@ zbf5cJh9PXT(_-TNgJNwH&qNmf!q;1*Y#VFWoBM@~_Rd)2zXmWo!Lg*^#9n+~Bg#L{ z6#LyBMeBUMW}wU6N0<9D6o`Wr@70VauzT?&V)uf(y;^#8kaJ--F5UEuBAeIthZO4Q zH8?-@3sZh$f_vQ31spV>d~&NZOSv~}BK7UO8~;`^V(~~B?Z+{8$_7dWc4|^d=;Ihz zesT$d8tDWWWOM`LVExQb@Y8bOi)JSFQZq37BW<(t7_5fw>wGre>tne;3|T?@9r$kP zjF`^a^>97Y!_B+&H`m#n3e3bxqaXDj+WU-7(|ps{C*Y=>RGF64pZpov8zk}gQXLje z(0H4DU0CT*Z5j8^s>UHXhzZwDphfe zS7W7Xe*eo6SfD6p1TB#pl%E&Whg{kUjy#)kPM52)ppj48>YU-LR+3ro6XU>dewJYB z{+S~86n;P5T}E~JxyN7@=Wz*EfS55eaLz_I!eI8-Dm|mByDDCjL3kQ12d@#_Ipoou zQ(g?ZHppmf&ELH>gL^;t(8rSO6}I{D6xeStPI5vc+r#n&yzSq|{RBL`+~y~Jbw@Wb ze0I}ZemdP52vFNNgXUURMf+6xeVf^0b#rWCLcGU!6fZA_X+I<8$8{-GGt5%sgnm!? zFda$+)h%@cqx~{LO1Dx!fQO^~j1~vL;YuLT+v@N=T37vZh}5J>GZdQg-2qZ&*;3q0 zv1^6BYb{J&Sde(Fg-!Y}MC_+m_^s=PIm(^RS>@AQ-WM*o?}H9vgy6KOo|QlA)(1AoLT>b(`(IfMa^ z2NbUdfzQ&;bO`O#jr2q7^!q&oUR|hXj6?jpPF9_5XmD+WrdnXQ2JxF0XHNSfB}7VX z+v|qhE-$iR4Kv9^qHS+qePHqH$DEq&uK5x@*Q*xP8F)&b*7r%DiG3ne2hh6>g^YZk zs*`=9dOM4^D`o+u6cv{T(SqNHy65fMV!^MIgyorrJV;7Yu6&0%mSt44*0FRtC}0L&{qjak8}p1W~DBSI_!Kx~aRInGz_by2x3cwfMA?-HQNvW=bUdZ&2k@lVu^b3sw5@v9r+*X)Dz*Q@@Y6_T zl@?jLGrwT55Vt~KKR>f##uO?L9_P8YT>ag0v81JjD+CqkbakE`TTd3-9BgdlNFvtC zQB51JeT%hS4`GF3=pDm^o}dBV-qV-V5!Nu#f<=oW&0qc1TtELvxWTZ0Ee55OEX0Oz z_IcJXR7lt)cUkwd%dBNe2q8}Of#|~%112;<^M;biyu~f28nNfTw&W$CT=Pue&u6p) z#cec~sD67lwM^m6ZoW7+mN#oX^&*$ab9!zl;yu{|E;aQRJ@iZ1`!K_k8TsE@@}d?_ zD&yuCfY=*hsV3nl*(ba5?V1`9<}5Ib5;>|nqZD|vb5QUI^klT<5EL;H5Kyo=Iylgw zqr_Y-_9CTt<9zi;bjlh)FpV`l&Hnk^eMNX3t7!O?R;*qoS+7EJM^;K1dV`~$zL6BD z$kq40`4ZLcXczZ=!c)yi6cx;#Eg5}G6fp3*x3BppOhJi_KLa3{f${)^Zp zv2KXCVaCem%Po7lBp~LA!=Z)L7zn8sy)h}w9eFJTQ&@4191tU47numOSfVy9nM7wb z*PgT$j9=Q_)`mmZe8=qjj3c!_rQawjeyRAmfp9gh>1{Hrdf{C@o$K%~D^>V%SZx?N zYq(s2#D|47Y&?|GnL_!D?F8JMp??CzB7c>=ZGwDIrnhu>^k6on@S))+F5MIZqo0q5 znzvBdOzD#0PMTt#CIvgE@-O-K`*K28EL1Jyr9H*pL=ZSr6Bw-%bJJZALj0}%VN#bC z@W45R)H)Mf{b(OXqt-OsqPjj`c&KAbRr%q|E9^-8iyKR!UNDVka`eHXK8<3cloGOn z)aZf~CbMwk*q^XpIw$lAtFCHT!mHjhmqb)5Jme9peo_q5{4Hy;2apMF=pvrl@`PuO z9%S=uSR1m@Ao%yc>}GeBCMf8*=X@6OX>gtUN#beUL|M0jM&Ww)KiR(M95UY7Z`cXU z_hyfTHFXaD6pvsW{KE49DXnIHcw1d`rIu=f9`HKr#fQj|La$j$(VrCkI+iHH9+Wi=M(JRZ|&qo@;pmIb+e)>C!Po4iq5 zw&i>}e$PPOi?I+;x?-MkTbSfQi`&Z4UtY#9x!&p1BO75rd_94jObR^O=+Xt_C^PeyZJ*~ z@-I=i(3lr;(ISz<6>rTAtzVZzN_qEH-8ikz`?@mUEK5$OWgZFb-`O9+4TcHVWAfb&Pi z>>e4d$)8fLKNCgp-`5xb24Mo}MeThF8mSzP3_mSoiUjL}i*JTOtmTI3WHG2bGARA6 z?+V)T@0V)#wAJ;HyM{w$sWAmZ)_gRK)RClir?FMokE15_+RP$0SyIdKLi&HrnmvQS zyWzm@IEEy%v+E+)W{81cx7V}b*{q>A+UJmUkuPI<8dD2Ikt^iYCZwT6IE498>Vg$R zu>1RJ*|e5je+M42iT; z8A8B}c2}Vyge^$Vu_FC{*m}q4O1kF_G@018ZQD*J*2K1L8xz}@NhZ#TZQHhO8~41w z|GnSthf{l3*Y4A2)!E&vSJhKbK?OxPeMoZ6EWTB71Xsvr{Cok80DPcLMV<$Dl!5n27)Ta}tOC97?N}NRf?8o^9Y>a~>&e=+-coNqw1TM2o;2h#)DE zPxqK(4in$vL=}pk48~2mq4`TP^kVd)MsZ5mueJ|FH2h0X%3X;ex+|^9PU2s%ouDGu zy0`t8oVXif^{ZRx=$wXzgu|DeP=wl6l>-OiX+e*Ws#UrYz-*xQEM2H!F*%M-3(=>J z@ndxDoJ#P}@^laIwh7OU8n?Jvp;Sg(*^8ccWpljJiik_O!~6y9VGQ9}VfWYU4kf@ZhGU z^ZjAmZUo0uUCh~^)RP(d3Eg35Pmzw=X_{xUg_o+DE z>!{q)Sedo@^)-=_pE32I(e+8xbyU{sBA|v;Bb`50t~&+t>mvDDcX#5L&bWyH1p2rg z!*dFJ554`PZVLMRZt+~%0D2ssmpSx@^_pAa5pD{TKpy>vSM8Xl?x<{WSCe@Ib-@IdA~Xv z!o-xa#0ui()vM}=m0CdT);L&|+eV0YVqxUf}cW)&@Gy4Y@&$bx(0Jj>bRKM!Z$jyR=DPUj+~@Ts}}Fs~QG zU99^D2fmrCHa0?ZFN`gtxIMI*S71zU7%+~!15S=D(4UIU@~J)*?LFT58}H18BK-#GAXe`M^`jQ zqm)CGXj%=GqO3%!Y})u!=f{DuD^uBjb|LC;1ioB>vars(;9q>Lc4ZoixhM1HlBs6$ zE26U*wgv5)!1nvI@a&Ddi-c+8-0;@rxzD)7Sd1@pfxk zrrd$0b~t+*)-C(}n3IgFprc%ffIpLs&b;-P_M`#b`b2|z6AU2LE)6(ZnPscrOKG3A zfKW2Hku$jEv{$9^GJ-4066l<*EU@A@?4D$ddIsf_S^JT$%9@JD-j6rua|`4b)6f>Q z9dOZL^H#5Rg1RNKn-pK1L%livHBmjMT78q=@(~(kS!}6}OgU6iWbUl2=EBFV_)QuGH zM0Y%DA2z%j3o-HB`BA_)C+Ybe} zNuIPkQKgbjyNX8AjNllZ%R;+o=EC?6biE`=M=z|B<@a*dbaCanWQ@-K-g68Dm=JTQ!I1c#TCl<>p)d4f^}h21t3 zb{QfFR3jSI2}YmHacJjx1+Kf*F_Y1EqV*j9_d=y?^13HY2INp21cvgdiDz^C6){93 zn$xDpzn34L11ZXXrH9Y+p4@IFOAN%H!w8Z5zxQiUXEj_`oYxpiHl5dOd>5V9?sdkk zs%Nzo+7BDB5H|j^bo$;*a$m}ShK~7GvrQS1vRQlndO;4`0Nhk>-mRPIw`Hy~x*V|8 zNd&;y5M*3uGGV!FK96Hrhtw;xQrmiRS9Q{CP<-Ll^eGS~gE=_yH1uH2{UUQ&LbD3KtMQ#mjxPNi)bacL8;Wtu?48da;-Yz#VH1cXkLuNqDC2Elq}*&1A+dPj zVfSkxpPUw!a1Ue6%M<-IT~@dhJCJq~t-rocLuOwI#yL~$*h@tq-JKmb_WT&_4Q!hh zA$`fqV}{&`MIw(v0t@r&uK-$JTMj@Z3zXc&(8-w%1?C3>*^CE=iXBT$rJgy67g+pH56>HsfDM0S-Nne-s^hN{`<%>gWRnxFS$&q@?ZJ@#x>xI(1~5o?6>& z>a4ac4`SNvMsiH|t~FgQRrwiQtkFSz!1XsHyfIxbc8mn@Ch}8i+3WJV;eB>TpM1j} ztfPa_6@g?x)pH^VXG0kdOP>61@@EokM+YxgeC_04sy1FOdw1ik^t1ZA3{Zau{HCyT zRjJ6;b1D? z;yn94aX_jO2lT42vGdSV!%SXMjEWAzRwNIZdJx3~e{Vf;2JK6c-Z?MDL+ z=voX2QDKJdgrBITAN(1f?~_QF@bj z_c#RyS5<7590sraAavMK%fwyEQ$`A&Q4_KEteIZgn@e;Hmeoimz3Lq=v&bRR+&WnK z;exR~dl11GUdXt0y${nPPO+LfCg%K0 zEyiU80mv{gVMHJ)U$xS4sU3t!kHzXuUND;>aCko$l9zw>k*=PI^}$VN5zFmCxqsM8-0LCeUa)jWFF3l@%~B!o3bg5d6_)3yMrmT9e-{`Pp4M z-iw|WvFBlmxv^!UAuiSbu^x#L{#}t!!G+@M*x$;4rS8=1p*fuljQ9KR)&7ZrXKsUpWN?rFE;@}; z6<qTa1^H=IBh6n zoQafFV}zN?YnwlN0(=A$pjnS3O4pOUjDL3fh&_J;if(*`t+GCGKUyilisj=GB2+TJ zn`Xu!@cBvl=RVDkp6bAI$a6-=5E9FG>r&%Hy4jGf*JKL^XkG)LguV~$u5YfPpo9pX zyS@&YpoE@xi45?+K5qcu`%J*jxKKiV-+S%n;}+dF{mnwZ`8#{Nw+KH5@;>W~sUji* zzI~@cOEbD~84EZocv2qKMP@xZvweF~48uge@G-JSa! zK~Im$KJ^l9^p{p`LUm;dhbY->OrI<;kqS_HyZ!ueR3m45>W4(~teX^x!@WFatJnw-0 z+gbe8w;Uh2Si;sn=zv~O~{?(Xv%WNDaKG(Yx_iz73rVbT&|At9v|_z2pdjwrnZ`J3pe8nw1uPh8AM0UV z2|E!{Qxoo*ya}yAY)4mTN=KxWm}NOhwJe!}0=%>*%K77knv!qSNuLHFM%iT*ng${_| zVys}=FVCHqqZ6M<0n4ZY%W_vNJ$7lEbd<30fh_2C@mgE>`I@d2#RGX3`zo`k&h

T_`5VZW4^z8AmG9quLiQrUYeR_`2TqTO88)DV4@$X202FW|s= zYTUWQ(5*QMx=oxUPt7iwbz#qhm?e zW}^dn?W)n+8>4L+-vih9H6Kmv(qA0bIj$uslDom6@Y_Og*7tFHYFDEejM0(#V$A{K z;R=-2_ysL|6{1C*Em7U@$r>TVlDU>WTU7RG+TwfEYK}?~g|6>xQ}L<@CwYcJaWAqQ zyA*Uwxq#w|5CJ}-`*M)b$XGN<*~~MA3Vj3}up`~u0gSwhQv9dUZ*5E>H)JyS5=W^G7g9*p-@#E|8Tf{laEhv! zF4mf?0^-+{MELb%O8`_9wWv_=gn`{ zqNBFlyuo_}sq~*uS4+hGWql&P``li#5@}OdOfgwpZ~3z?jPn;ZVn*x>myZIMg#*Zn- z3JxMI#`y>pZw`mBb@4I~L2)#ASum8Hq5IE7bY8_yseh^7tdz!-1vCR&ij2T*n% zQ6I_il^e&94D~WwF~71wmy1FhcJ{5jh_}T?b$5b&JMyLdP;&a>RIB6ol!1n(=@m&`L3_01uXApJkyX+tA;BR)3rP$Iik_oVzK`@ zi&x)t22=ZZFf9kUSPZa1VNC~fM_owVVMdVxS-g$%b+M~6nhZ9W({`o7y1{aT6(n3x zSYo;dxYdU`vSz8L5)h34>^%GQhgz9iV~*>=nN|%N!gHJPki+R7SQUIWLs0N*c|ft~ zKEZxArR`@C(N^<0fXENsEj|9~Zcs4Uf95>mt>elaJkW)`G%+vhVP1iezoCAKW6KQm zBb(~v4ypps6EKgs0X}~nCA3nIyW?OyJnX7ajvCW8DKY9v&_04_u6}v%k{r1@J;`BV zl5^vxEg}RGFuROr5YJ{vaJ4zk1XkWR>bbm?&C zg(9NHU?2s!jo8S3ba9iFl8)lJ@0cAYDb~ELtJUxqF}K*Mbn-?2VaPY z6y@9{7Elro8gIq5akoWg%?R?KsjfI2*BJS5$_#l8 zYh|O6?uA~=Ox^#;6j$>EH6+HgNXI&8j3&QI)~}9mSG4;@2@pB+fW#?2ZAUo;0 zYTlO^E=`$@(huCX8yr@&tFhrIt~gWRSqN@mYg@)EEIZWXOCc`q%t92AKKcwj(vdw} zFufiy7#lh$Q3)9)?LQ`D(7|m*`-9*|4NsZ=SRL0%iAiC*Vl&Em}Jxt{a33= z`zIXteV3v2K$pe5!=L(_`V#2vKik!xn@NVUC0){1nEsw3^*6U(PE-DG6lUQH3U7mP zU9Zh)dk@D7EZ%uZ`GHg>sg+`|1_5P8D_ z1I}4J6LbgUC=4rUy(MISZcvqS{SlD`^LG`_6_@sk73A-dissWrMZ186)Mzk&F!grKj-{T#K}*JKijkf_|<`yvM~tL zRay!RaFcp*ScesmzT8P`jvxO1Zc^Aaqfjyif)sP zDyDgvz0ZK@kHF7??3;yjA`*HKqy~-J$uquHI;}Av%`Xi6!FMkIOHye*X4g&_G`yxA zUTZN4ht%wsBg}5rZ&hMhmZGRreZ|*C7himoTi=51*{WxiR&}29BnPVkt@ID#Kz3W0hCxhg*;GFF1+O&cXIMF_TR!`? z=z-FWB7fTaFr*5i1m0=Z}dDeo6q1V8k!kg)}qJcs$Qc!Nf~QB@>dd= zZli!uQ?KckHL za-kEiQUXUtq4sfbZFl8{J(uLjSEh{^~o9Fu)IrH*In5{#c-^GWbqsLj2bE zc3*MDp{t5khdn7`Ki{l5%^BxOC&;~oCP|yClzt<;n}y5jG#4w*h{Q#DO~b^d6QcJ7 zC)C8V%%$HHkzXfu_YRw{!~Leld|_fFAg^@UC;a&QLV1+JdrrP@O;T5j@VZ6UG7uK% znTjn+y?6c(#_fE|J}~csLcwEt^S&DqU83&)9U;cm95bMDfp>Ryc>fJ*2GTJr5quTw zji#V1e+13^3MD4QgUwT*HIon028L8YK939yjG$~>*bZCXhRq0BAU(0bBg51sx>%5h z8KPiMGGM(RUPTCuRO3&>n%FwxAY3$<^3)=@$g#IqjE6 zO*OVK%m5(wPcp1o4dnuPu^I#9T2zN&C2aHlgE~)UH-kHm|7{X>1{4ixYAAIQC}tb} ziIxirg3|IZx`#;4QpX~PD_L-K9=b@We9)Y=#fDkxC^vWb-Fap~mXu!-@R( z8rH8~UN6LX{*^WpQ_t5AzC_>k3ftjHMdib#J5X}Kzbsj-Plx#1VAu1?iy@pK1eQb| z7@CpU9y3N;#ABIl-oW+bVS~th|4TLeS^chl7D0B960kPI&KD+pD=?g#Kt0M~It+2r zdhI6k()UPKmeKGn{andyZ^5F%IvsUEmg<4uzDF57Wm9y&NyggC+kgno-O(?sjn#L5(HB?4WZm-2n7fAHfY@#vvRDl+b$fZ%S*pwEEL zq3&^~3^9BLoD4Bh23qgt;-)KZIwUP|IK~>Uf%zHsLJO&nlAx+l>Fxe0?pbJ!s5aEsW*ovwOxFc z15Z@|Zf|_88ewxcIvFj?)a0y@nHRUd;oy{ljq?A?i7Lf|+Vg&n=#fFfgmbL$jX!l+ zeH_u6%w~U0Ojty!vJJ1oCEhjWGknMjO_EtrbZClAs43FHp*Bli|22%-A2o&=Hq?TD zGhJ9LC;_V~Q>^Maq+g*SrJ+Rzq3yKaNyl>lZyKk?v`3l>7A z$6&(vd2v>w6GWj_xs|0ttD1}6|TJ$#a){L|JJcU3) z&dkrXwzEAWCTB>%JO(j_Q^0sVen4(=m8*9xSt92K9;pGu+G4O>K_UUJ;YExx7Vk(8Lp2LD`IrpP>NQZTXL4aU z2cdYN&M6Q%CS{6g*dH!Zgr$%>JLR#k7qPMHXN@=drD$A+`Nl1ylOerE;MQRnp92J6 z`KFgkD>Fd=@{2b1C_!ZgIt)f{exolm%Z7on5fMA#6~doJxxl1m<1UvTd$NwP8aSbM zQ`WHMm_$b%x0p1Os^+2&NU11qn{NEwQUdmq22-hC0!rCv!d*QnhK4S#kdK7|<<0^0 z)^q9jJj+V1h+AAy@v?YlKzEBnteG2~^&}DPv4&r2$z9 z*72QUEkqRj8}uPP+`@WLOIUqfg;Oet@R4&+6kuaN z>#rePwDBOl?7>1_^r45@;A5q4wZ^5xVta>iKxxjJgrfY91xW&ix-Y<@a>$#Lzr%It zi=Muxofz{Q?*{r;=uGZ)2uACG29yag?Kug(^eeiXtcz(kSzU8z?`<`Mk;{k8cm{#( z`ONHL39=4{`-aR@oEj1znnttnafa_Ji$lgKMX3Yb*|ZlLCDi?|BR@KZCw#Ntt7vJc&#xxni~ocnBO=hmJOI&NyDTK)30$AYxRvF6ia z{b}mD?>btYA08=7=caWuJg9@(1^>Ij)_vT(+4gC;&%AK*NYJo+P5fw&)-}Seb}@L# zn9h=+NqbI^*R~NAsU=wFcrSW`wnYcRqhiM$P-Irs*iczy1_<_1P6vv~IPL!oRSoLB zoB!{kym@U-pMC`$P9Kr?hSdw8!MFlbr*Y+MzejzYuB9+kd6xcUX^(uTQ^m|6hN;)! z|B7nMN2uKWAIWfl^^!D(lZ{eMF{2j2h)F|n>3>n54~@gVgk{>>v?4(bu3rz_KEC+w z58}*^zweh7Jr3`XBmzaN84WndS6pdW3^rjg#h6Q{uN;^J;#;JPjdq5--H8-WdS1^< zDzbllKz1OVOWWXC*^&Kiw4DjhZL*ySezK|;dEQK$(FXZx1A0^4h#9!_qXv)p|HhZ1 zw9Ji~`Ls;k89_Vqx<-(OmGVJ#hNd^}n#JLhy)9Z}9SPftNV_s++1Rv(_&D6gs1-Lp zYm8a|sk^?-e?ybnKvUGpAi#|BZ{x&4($g$UGVtJk-(g+5I2;6M(imWDl};s7UCQU3 zntcZoGY`6Y8ILv=}(EJh8J!U_X0_pve{{9b2rGjig!EY^&kZ<)*apWYl=S2@&JGKH0{Oj z3VOHEUt^7VSb561Z>)Q@KV~z)0=f(4Tz{bbHvSHj6hHi3QF$39gN!S|iWLq$WDNgd z$y-5}kb}`OqUJS1IOTGxV~=3b5<0|6aoEH=4b#t5vU$!7PFD}6CXp`Z$?lg+HL<97 z_~TTaIV=?-41Ozo)ui`Wll7NU>jGoywBM-|eTJzJDX_Q;x+5vgeLK#JoiS>Ov$Kg8 zsW~Y@WC@i$QX>yBjR2#rctE7)X3Rt8Xf>*O`fT&Y#$c{)BJL$(D&utgrqFqc=KMWW z7hXDxD%=9bH~7`K=FZ~}o}TF7!n&m1Ed?eTZ=C?HK_Wo~=V95Qh>W#R>9tiiQfIPG z9=Q^lkn{mVG_adeS>fH!@;P6SOxLc`4l@=hmR+?eXszr{%JbS4Q$M3%WRfrqyziU0 zS97RcvqmJ1qG+6U1{}5U`OpK}Sx?MTvy4vLD|~dnljs;p&6gM8CSWE;o-CcjTTW^#CN3Tj*AR@D{JzC5S@8rT%w9oDJSRqLGfF3u<6q?Ocp zZZStrG(@1nSzuu{u$@Fv{+3*LNh=Dpt+yQ)u=rUamc~3Et0qo233;!ICSJQ7=qEbw-ojawr>Bb(M zb>hYZ{DvN`gLb{`-+NMwE71UMX}aca3Vq&L!R=HXF$_VCIA0hXoqT?dKmf{FxG2um zGs8sX4g|BRpIZ}Ps{04^l4?aVo%s!rps>Cf{@ro`RtV}RQ#ZZM?PrCCtSzo-QAJ%= zNiVO5Lr~g3OO7JzLt(zv9;bU0209&+VipWA$}Xj^=YnVghhE;`^wdr?Oq^Ek*OGwM z8g|*VP5!#3gf!>dtXWU*|6+p}D7I!o`i{Nx{1l{$Q1HT)wM@d~)F7&)D|W1p93Rq@ zCh>}p>V}24=(O>oS+*>VxsIwzL=vPDjb_npGc;Uj#t7J&r=AlRg!3?mzs&&e2Q+wd z{6Rn34l?jpdOPHn9)ip~8XM+1+_g9iMI&rh2-HXS&eqFUb^XRIt28hU>F``gjD3j4 zax7trTrR!!V@;W+n&y~oD5RpSK2v}cm%(=aT~)&|{~i#hGInX|bAG;t&fb;BkONac zMxLyOV$=!naEzCNdHE!Vzf)(bD{6wYM_Hva`a(>;k4T}g+U2B?DR1XlW1(N-u&dKvN3c6{eLz!&YrO~b7*61?i z=!xNU@H;H$=MmIT4Dfl5&}T_V;o@Op0wcUT*^cUQk8d>z`FqEyYUp&h=EySEN|+4F z)*J)Vcg0+S_!>(ClWpCrlYv7k%-1S}ob5PS^g^{PS$^u0cSiwJ>X*&&4gozzPFd|l zSB1@}$ubj+`+JY3_SsapFxvxiXaD_&kzy5BAnlFMUoc@EPwM(0K9Hx2YNV9P_NI5Twg~50#E3IT=ztHJZFH2i=WDojj@yfgitK zOpT? zh3pnwwHA(s5vzD{uS8UlUHmv1071b2lW%{~AEa0g`+(_s-1g%OBtI}Fm7?d8S3T8R zj3@r**a9>?N8{hI6GqSqe?!DrcJ?yqSK_dG9dH$T zP)c}owS)gooh(1z+hH(4QPSxLGt$bTk%|d4@{aprO9{x_AWHS)mKP zgQCO-j|)f&A7@xX6%|t{lfO^V=(cZCX7S_DO(!_9`xBn==?#{4SLK2BBfv*DBkz~M z#Zd}&DpNBqIs;%M@Hr6jZq6@zb?o^s7XcgkSQ*G0bOerIpNBAI$|f9B(3QJ_Svl8{;^Ir~wZh|&b3ZjFyJqQX zKFOsu9 z8Sk4%@>kh{hhrdxE`cz+tuIItchCYYnuE=gNq|*goo4XS7G~1 zckPIK4C~QhityZ&o1ze;5nTIQTwQo1gJ<#-{1=!8CV`%g`r7Jc;4pII=G{~# zCab_mZ&MSlLM zC37@Bs3FA|@r?D@O?N#7SDV?8(ljWiOve{m+v8=aa5ifobBkEufrha|4IvWOQJRA; znDrQDq&`bDMB0cgUO+OF>h!{N57Eoss_y7l_q8!fiiYRsZ`M*9a8L#`O`iPd6dh~@ z?2un9J|f`*d%|4ACC)B53Jhd4)}U0HawAA_XQT%W7@dG~1=<5~v};?=D~cx`eH3f( zB!QBN3wzi^KUH1hV^nW(mZ|%opuOqRFCo#>pW;y*_12JcOPc0&hNMgi+e4qVh!hYC zXImER#xlwl>}ZJ^>(X9{#U)yl{@DLvdF-?W*GOkZdqisg2ffFaXMtL@*w**e-7f|8Rs(XB z5kEwjwty0RMpzl}Jfhx&ZHuRETBBySFSu2}tyc8OC07I*MtbLXjEO*Oda~_i3bj~wV$+Y|5O!5#XKuyRoEHM3lgI9=Oa*<8 zz_)_v_AdBA%Xw`wBm!1tvm4g?YmLE0aaUB`fu+xQURA{1g>@uuN2clS#>(D}3!5lR zEyx{W6sh>eRsOi-)lNrFqXFQkKZ{A&@qUcGu;K1%TWc4;7S+^cGuz?M>Bwzu-`*Ti(*LwamT? zgHlI;%}8MO9ixbvT4vFw2I8Q8i1(yd8y&4=OwNNsoCZ9Vt^GRpXUclp--t)fY0}%N zO4+Mo$PlTp{u~oxSgl$Wb7&5XFm6RH=16tX47hwlnw-vld+UID9PyX}qL08Zt&tR? z!1C?~ci4&kDEykQQbl9CNitR0vl-*7n2)+$BV@-yXp4H2@@Az)qPoH(a%=n)Y`(oov2?hP#=ru@{=Z} zQtU=Hyh>Pq?#OG0@fghOi7jhPImFNZWO6V_T=wuSvnKz>mmlXlIqN|`b)ueq?WqlX zLhY=y^Rj`wzxS{?ExkeZFaMcgnQm9ywEP2#(ZL$$(%~pR_O`bHIO(o+zuhRP;J&`=23p zULcKwsw6pj;)tp5A0#eEeg`t!HRx<1kvV1yrSp%#>^UG`8SUr%(E1A4F(Ujz z866@-AESGd9;Sgh$gD&x)>%$F z*!f?2^psr2{9fUtdanC@wIdh4)_pAtB1)@=p3`WOZtWLTVcyDI{;U&*hR{8%zndDZ za@V3_!B%7eyQoDiXc87&V5##6fyrUy+c8o;4x=@#FB`>{Kb9!=4!IO*bJK~-ytx^=4D z@f2q!vHP^+h6#j@Mn{O!i)NjP8F^NFl4&0ImKCE;8?cZ-5jE`)spSwx6K0lAfWmGg zwhAjs8LD}afz#Bnt*!Q{^3r+L~jP45yt%Ie) zwscnKDOfAjXM6zxUZ6YkqeJ~Q^mnifKCl7$G{R+ycPHA}{W5Cm%R21?6ec>g5@=WO zm+uB+;<``sr6^f5TXhrC)$EhSn4c4q9rm-r*$evxrd`j;*`*0IHn646?|3Tvhr&iF zUwWrP0D>{#sSHTevW{qn2GyGXtP6$rvpHKWu>1 zKHx2i&e`3lvSMpfRHF{7^S4n&lP(Of_GPNFa&-r2Ce**~>9^s^aD;kspenJKBGdzL zEq^{8t+8I_Fn?_R%cHw~>iBSRCH0c4+i1Dau|sTo&k3ojE3_kROGTZX4AIJtwO42t z5;V8tY;)7ej;(5KTs^^T;Kb7d&L^d6By8?c*c&*BdXE4=O$Demyh4`)8b$4v*L=Zs znwD4>kH}Wa`#JG8sSeqGYM)l8eyQ679=Mu;TMiSr<;_Jaf{%|8p~4gE}nGv1;r2ao)lCNu5Q%bc=U@lwYmMj*dOY0F6rye8@3$m@Lz-VD|8ARG#Y zqnC402J+s^sxNo%}Xh zP&g~CIPurPU1@&2mNtmCWT|E*>qO-wjX~&|YqmjLW`#KPCfio|pMa|C+}GPJfc}c* zBvnZTtO}_X;%kX|q+~K%!+yDssHP|w%ShP<7$o0gDKfl`Hx4c_j^~L*WG0~zuJ?bE zspTM|j(Z?x8u!&fE3&4omF7;V>Js1nit_&=nP{Ja0=8Jxz zBM$mJYi14h>j86C39qhc>unub3)31LIS}|p#y4HU+WhJF#WV4v}v>HY1Y%Ta(=f`BFZCYx-(g@?g^M*qa{&$Vj;AszR|}Kgs!%KfHx~nb*1WyyS0X~_@KH(8)K1Z)xSDVT zBcqtB5P(J-VW%A3DdqWw3_5?}h)WrGZNv?+8dO+9>b zWs8g^-1i~ae7pYChI2zfUN?-(k|>u3$2B!AXV-8&)5_ia-)gGI&{G~xyUV|o-)Mt! zg1!r4e6e>`zP9eht=n;9@9GrpX3p0)m0D^Sk^dq!%^wnTG{*+*#+1n)mZN9fH4wntwc! zh8Ir}Tn}KZXcl9vVI)KrX>V9^XX~F|WW*2znfqb*b@pOjVOC#ZMPkV3T>UX;6{O&u zW-W`Mq+wft?ez2MYg-iRRbQlV=!-XWoD;gd{(gM7_`Yxc{504~$^Stk&h+Puj@Lxl zU?ih6lx0UzkEOl^Dm+W~c~~Vodi=(Ma{tZ18!j$nL$MD;$5ndrB`+c3NBYG}d7J*Y zgsTed_s3F5kF#QP6dqVH7ZxmIgr1KLT$77)otuA3Zb4H`2p=T2@PG&$lQVHmJ>^mT zI2@}8^funk%gvUCz=f0+uuaB;YMKlO zLO`AEgbJP2V?$z8oF4ELk$dOrbFP&G+)kXaq0aJpm!~n975(LSafv%Qa0Nv6yi+P z0^iq#nRB8v+Mpvt!<`M0iQLWMjKLfgTJLCkBpWqFOMCI>B@AD zEzO#F2*cq*Z-Q{->ahqHaL|_t38TGc+fQyGE!xr(jYQxXl4(r6h8*>D@jJHQwtdZnA; zA?KZ(Tn&=U9)7L}@+ZghtrZXPN{Htn95$2?c+Z%yI7%JDX-xlX19t zq}gBpD%4TMUhEcu*N^$cDT2hw&4dXKTdH>Q8CDi?`{EXw$JHA2>i3X@~RqI{q`Qq++J<$x=)|U)xj1KIb`1Px=(k$hTiHf zakbw})JPTCiG)dtDRe(#>FiHeeKHflx&--^P>MJQQW^}`(A!N(Z#4i$!v&8zf8K37 zl;Bq0rT82+A#EnPoK?~do@8DfeWEH>6@#&}S!r#_TU6%cM3+vkX2z{q9(g+J?yRIt z>e-ZDkH48$QUZM2MY6_^gdr_w*^)L{{W=&`J?H;1xj1jDMezA1-jMKwU2ukD^Zr;J z%?549{5nKL7TR#$q^`8}a}*58qp#}g-hSt#@Es|zO0f-SoFa8Jq$Zt`Jzh6c^( zhHw^Pp5!@lV2bn3K#^(pE)m@u8gS96%apdOstoN)Ha&Sy@8bJGlMjq_g_h7n1JLv3 zUHnkPGVx+aiie=^1l#wAUMsXxoZx4~DD=J`5neY=zLXp+AXtm~oV2k09Z_z%k=n5`&xoFiI-W#G!BZh>vo;+dGm zo2qO=p>w8rS9FrIz0)*;T8%iF1WUL>RS1%IO-&A(<$uIaTv|iACdi3VLQcY;u2k`2 z3arlGC`y{p6=+`co_v;CNNo5yx~wx0j5H?F;Ix}*h%s$Wp7dYdI>|?wMec5J<>P;4 z_2NN$Jimj?X-b&Yv<53+W0NCmK9$x^%26D;$GgPakcl zTFk{+==viFwZO6!j;l-p5pUTSV8SxWMw9c6f5U^aSP3PmXQVsTK&m~fFGWVdOk_Az z|AI2y-VMXK4VB^HGBCnOl5p7*|H6?O~%dl>)7}rt+#rjZ6Iv7Bn*r*0$BZ z4-YA3Q4*!G?SkC{TLAR;yG1vY84!J;gVtr^&-v5y$^)N%Ry1^QU=jX?3P#9R46fh~ z%rJU?*TcVr6ZOclg@c;Bo_eLWU}JdcorF8^hlW;WezU1->apOxno1rA3I6RXKxFgx z*gE2J+Ede`f5-5@sYGsgJ}c?X{NM$%C_S9a%Mr|w+{xMj_!T8>a{lFpJvtOPXpx6D zHZ7L?Kief!g|!+Xu*Huk*m`&HW+uYRt;TxoylH(GZ4&fh1bHwYiJ8!k{S@Mer&5~_ z=R;XPl?BWb20}NT3|tOXhTh)?Rp^ayXmDAQSO$wIBwLw*VP(@ENnJ}M*!AWJ98JF# z#M9%q12>AIC^+{hQzwqiobxBzKbl2-6QF%tFw2$9hatK>BP_Bf=ziJ}x`79!54(sL z+L)n(^{w}T!659o4i?7t2u5^GOUO;~Q~;7nj!*`x{|$?4ovBIMVk<)c;30beiEY>t zZlAg>aN=)+V6-k@%n{lc&b<8PyC$*?TqgH_Cj&Ns9$Uukt7#0cv3_?+&H5J|$C2`e=9bFHH| z$pK(H`F(4YiO5nfA(;Z6-|jke?{qvHCI-bRLDZs{w9GHTNKY>Z;{f7udNYxBt!L$1 z6L(W;le5rIsBACQ6MPP_n@z_S&E1ILDi=L{z>HlS9nYn-qn6{X8X$&TOEkLeR}I)V zc$<@;`Rt^PMWMh<41~Y)z$7=(16d~Fs!hx{*Uy6;>Y_DfGc7r(H1EXAuxMqWSfuv@ zi=f#@34#d~dl3bGKOfnfYMgzf&zK6GUa_gYN+pg-eZQJNBYxe)2IcLt`YHsq$%!pWVw|4GW zZ+`K0wbG?|Lq8l7x2)C!di+U`{>-Di(Z{m+_sR9#%OGh7XH3U_$nqhX%=zDs#xds_ zbeNXy0yteRIMr79qv@T=muj{{{TOz~_P=1)vK&&M7i@)YVk+T^^jte4zLVQT5#Uje z{9*gz!pIDp=CnhNZSr#Q-qQs5LP*Q?T6~}13_0c;!5h3B(kWEQn5bi`UQUXC;`o4k zhHi?B$>@-7m9<%Fdu^#`_U#!q$>e$a_^wwb-KHs>fO^zyiHJY{cvP{(-e%LHVt?Wh z`{CN*L@=OFfpQwj4Thz`@8eyXOP9gAX~#i!KWvs>Tk&LORTH-VV}t;1R1gI zWIz1&z5Y&c+G=C+?FW8%$-Aj8Dff0`>zR>dH)_sPQx;Lwkn`lSphqYwjFKzq59#0N zk|glOvj#4xkcgjUVzf?XcT(E$6G;c?{ZCU@8ZNYGX>_I%6LV3h&63ld*DX22>dXK) zS;<^=iTkY#*W0Fk<~>v{i)JQ+(WmaL2XkDCW-g1YNrw?epL3jzUcnC7mNT0Rq1~Nt zO{#JEn-^%{$II2hGe;Oe&69O2rxN^0O+x3m61&)v0eG4d~b zN!>AfjO)ipsT*Ua$S=w1eA(&DH#DPlX;x&xeGr4s`>rHdpesxmniQZxSl_S&@+toP zH`KVX0*!+>_fmjH@oH$ml9N?dT;gpv*1)$bl&rGpV<(V~^h$hj`RlzThL67igoBlx z>4h0WA{dDYB}5BAF%nz;=gd-cLSUweoMR_xgi0lCeU^|EJbuEeQoN1o1Q;(1USL+|HFou7{y{2fR$raglqDDQefU~Du@4`rHIimvTL*PfyR=l5o!DCzN zbnix{psrwMwT~b7P56O;cB!RAvkF@xfPubRk1?E}&a@>XXpzm#*~8p2!*b`$Sus>W z+_ZSQCoE<+kA+>v{Zc79?tiiVH8lZmQwdrsNe#Rlf^^Dd2fVVDYqLe~tFJxVrDipp z0>U1z+)#+48zPhAYF3sa&U}dQIOSmz*oXa;$R`hto^HZyDn(4~)A)Co4E!F3u)Q1?PRU6~ z)5bA<(a3!`72ebe)6oY@tvv}*nEABX{mvqCKH0B8h5@k){&p+-A!QO=T2cC0o-qL< zQQN0s7S!uy(T8BIr;Z=7dKOf>uN8uG^E8034$3zV^6Bn!9`qStJ*k=nz5LUEaOfjr+R^E)iYbR@~tI{Bc(+PiwYzS!U4hlOg? zR1%$ZJ69YOCdE$h$!uN#n0A8qp}<|W2dU{9E)vme<}0067Sw&1b1>v?3=7GS93!(m zqwgg|fmnh=sl*Wp>mKk;iGD&cB_yeNhsq?ziYO$Exy>>+$vRi;`M5z$c;Q%Txr}N> zae&npOB&iz4tg>q2OGyHT|mo^YBYJV0$Q| z#>@`_`$M3jZ(8r5$usb#zGcqQ@3jI*P^j$fhWB8JSU8kCV>!&x?)ephwe{g z9(p+3<7?sBMxpU&>kBvJ)6t0D?ZCJJ zuS7VBxOzZPvofU~=E09M_=IsE?l*xcxE0_#ws~)9d~O!LN=1S@AhjT z<4xW~WbgP-OF3!61Yzq@=7BCs%x$bl>Mg);7F5UwV7mp7|5F$Mpg-52Z;zwMwP1UW9AocF%Yw ze&1bnIPx7Wah*JfE)rkovj;h@oHMaAg+uvuIpU{6otLbhRM4S6vBIoLoNTLs&6ja- z%yVnfDPj=?Z^%N>8Yr!48m)@mh66oFp=P6^k7ckpXGQ9u1A90t%@XrRW^7SLl%5-N zUA*5eG)J9G@N04~tGs{U%wQXDy!-SQAvek#p%vo5=BBbnU246+z!t4(Oq@GTvmXSG zf-^x7-+*y&*W^FA-r||9I#;;WyC%jPwKD@HOh{B2Jvxa@Ol^!VDVt?8cXd?_Xczss6&ju@sG{J=_Ey28w;t1<%a7s_ z$c;ra}hqS(D7t1>K@l2I|J!L}vCL{!RYNU2iCa5+ip{ebT-8 z*r?>5MsNv>F9q)x^r073QVxbg!lfy>j(Y;oU%zdql%3f@MhR(p_pq}XP;=(s{x;dF z91LlThlQv!FRHm}q%27>1QYm6*ok-aOZkNOY5WKsu<8I;bqxSj15V!%otRoS@K-(_ zaa;Zw{GnTaxqEGqDZ|2DmHvapnzG31Oj`g51}{0)MO#lBnBB{^Bm+PL^A z%V!TnBJ6ON!MEe(^X}#P9GfdCwBUvSdV!R4;+j?j&zSTP%3Ca6?1z#^4X%Wf{k!G? z6Ln@sm8B2`@1YIram!SyyFxshrDr^~CJ{1kJGtZEmBD9+Q2OfIX8t`HMMLVAA}tov z5RRoHs}8(4^M2?3>tai{M^%Kyk*LWU?;Xszv~ z3#G=hUoNw{bmhK2ZALyp%~#}fd);V{B$LZ8q-j*R2@d@fD}FK8ki+3UVps?m%Eg7) z5iSW<%Ou9){3RK_zihX}*|qo%YG}nc+P@ibBs1bis8(E46#|sUgY)B zDJy}Utca|Yi09Z+K2Ol8^9U51 zVHvh$`do=)6js;hR@F`(K#<>Lw%3~QX*T%*uK#LJS+_y4%oi#h<(D1_I&%ata^e|t z#ygj0*J{=@JuoWC*k;EnVVX$Ks*KA>{tkzMLIaNJvrdj@dxN8yg%rF?^yF@Ri}c&5 znSN%^eqr}OaM_Ix9VP`Mtt9WV;WDylwx^xc6Tlf9T3SwG~Lj<`AL!n^Tr&Ach-ZpYZdL+lOEr(c?i2lnWq!E%Of);$SzIQ8{YW zj?dtJU-R7LHo2uSxraxRkw75_{8@``QwDAhQh|z!iJhaNS4tDpDKfRt3bSH9D*MA~ z##c917YG)ZXn45o1h^sKwhw>%G#Q#!jqpdWf2IBwUu($slmDA8POEK=X|y&bJI_I* z?w-O`8kgRTo81|pqwam2MT_4zSRl6F8PcHixmTe*wX5L5O40A>Ctm$5UWA(*hxYoi$a`P2%O&nu=$|zX)kNi+FwY42`J?BpZ-H zD>L>KkVa~VQ6E}6pE|@`Esv^gy{>zA2IuADv0*CX=NK`wwWCKz)0YriuEWorkbRTD zxUI`}Nm$7wIf3Li0fZ-JH@p|H>4|Bj(jnn?i8VW=lmud-J_@{BIj&tk9#yVYRsWks z=&4n`rTPBO_=itYd-m>H+i&?ALFEv%p=p8JxUmW-|F3}0jTiB_J?2#G5qJp0uZHh& zYR$?k1M}v4>ZG-%t@8$8#3tOONGt}LP510;y1dED57q;yVm5A$KzKKx=@_9gZ$4YL z)N^k3b#!xhG87WspFho^MOBq_>#CQ8_HrU(?@r#vRDCMSWw-LBEZ}oaKnmZ!_Y@#_ z%NTIE5aL+!-uFDkg=;$#c0l*?ZxA@F;2A3|Y&8qWW5H0_55sBTylpr@CJ_~E4nmK- z*+*l9DbdzQ_}SAWGllCce@5j~w|%6LJ3;+b6k1RcdM6#S=)|)Ui2;1Vbac(g^V_Al zovFG_ahnAUtIrev9Gy+ppC`QZRAb-uJP`W`dfFX!Y3%+iKTlkG9dF-WcpdY7Y;-nW z`P6ko>H>zxf1)P=X29Xu>$pZAuod>tey{pYlP$6Eo1VwbKQU3_(8U19y8lRH?fBU9 zkQ=33`ft*IkI(-^=b<; z(fM`YkC|Eg2ZiYmk5fl=TLqE_Rb)iy@Py=cdUg~%%b9lSsXTE`KIB-V26u(;WU)13 zZzRcEf_gz461mU=J-p&@?}}uwP(?AOhWn}Jb*7lb%b8d+;;yoSDO^L8-TdYOBF;bN z(I=@!3!r3^mokq`&D@b8eq;(s!N61s!u3z8?mY=TvUAW;snHN4=GO`8rJD-AFf$)Z z;U=2k6|;3CCnXtnE9mRAXIOElCIoJ1Va2$wTM2RiE}kg=dGuG%PltoPHis#GN(7g1 z^NS3Pf@OsibZD6`cu3#P4$|TmEm3HH;-VP^!Vs(v*#@OGRO?;PcKyWM{hOfRJ=t8! z!fuOY(LPNQq#@G6SdZSQ6*Y*}rl}tEGu8=aVz%XAgi%9<(hw4Pei`n08~yL8w!qKF zdeaLMG1`;hgouM*Ql)r6xj-Fw24X)V^?+(>dT2scO+UNEkIXrkilh?e$~9<@EFP#b zfK3)Hqx?MXpZgNV7b02bs-sz1VF@#sn3|dg4>f0*;n4hR1v&52c6DSgn4gGDqk_VH zhh%2hALri>$bNJDYO?Jld0Eghp|4Y1-L3bk3@#DI0Ehsbt`ZBhE&bw)vOVko;;6ti zYGLFearvYvndEke?N%^^g)3NPog`=N=uEadlIcUGkdjo*lNP6I%T7Ch;TZ_V0dqVN z?%*FbT!b_h?ld2~j6q(5ult2Bl@Nfi>ND4)iA_P_qd(&~Vj(@F&hD2)G4t z6SMi~uYoR$Cr#YxEI`B5cpUa|6Gt(nXX9WyO}ds(=XdteUHze_qh?Csr})BEHY0#; zX7G2}ZX0&r*u(UQ2rC3w%d?_-(``AAIa|H}JopF4Nmli-bZBx{J(B`({U)TwL(wB9 zc};*UTW2_rmX4AVV@XG=<0}QH!rErDBQQS#@}0ei&%sl+BdszAQN3{Wbhl7Vjdcq? z%+jb?ih$};wUg9)T0ixD?dfl#{r6mIKe(jZaCjhN=P2#dV75bKM5*Eh9v*v9Mi|@K zV6Wt>-VGlW@(5C;#{4F=X-7567Vcj?bVcV6Yz5N-|4m7<_7p^V%Y&{tkv0k&SU zX~EQ*kxQ>>fkC&|6H&9p2CAt0p6@nyXHG(Tv3kAk^ocON_F_so;F2L9=ZbyHY00-| zUc20w(yC0k@19F{W!A&+QJx_;0sBVRL*;ryU!`jBbP-Fnf}!*jc?ou05a6RWNnz5v z0|2i4`YN8U+X+)S=b6yOnyWBp3ym&Pqt;{@6V2OREDY^~B5M&m2+b~6F-2(V9^_Px zyo6YWwmp%=d=RO>U!EDGZQ|SNwrt1=i1n(=2;DZdwpdpdt_%>0 zUI&Q7i^>IAzr8Ly5n0Ob4W1w31&P(KON*+PLMv8vgaWLp+u?Yyd`P{>M>93vJT zf_FLSOwJ_IhctO-WA;Y}-}ZF`l=4mzbZGL`^FwHPpMN1AiTGk2{@r6-j-AtS>tVSM#>_Kqo z1ZnrhTV}hfS(Szo)6E_4oB{ooTrbX^ZcpdBf#c<)*1)I57xbivR1CuA36Vk8A31z? z$~d@ABGU@;HKps7k-5xFJ>}-{F|Dm#M9z>t~9z2 zd9h9%of~Z#g>cxPOA2lhwxV3CHk6SrsZqNh#XdyII0J-mxBd?HS4x-RHOCFpUZ60F zyy9e?3$wW;^x3_pWI;+B-|)9P(me=423(TB+5CcB)l24n-^8+45sa z`{4@&wav>@SgMItK{7{NJ6mLO%lvmmW=mU&E8=qX6ma4R>uhB|^9|RXwPu3L-zQEv z!|;Z6e&FAg!gQZGRS2`n*4f|;R>Rsk=%>7%`!+j~$A$F^SkB?)e}6KU89~_EYi`{4 zzQLFkYiNI=?z-A7G2326y0U1AjQZqiVP=5xOX1Rn$?~3EEC13 zqJIvmVj4=t<_xt>9dC)3@4@H%C?B?TU16xP5+u+uRY?r*=D<`eQZBlINAm_%AE=gU z8^zpSbzw;vguv==hO4@M>2F}4qGt{HdUW;hk#^s;*fjaY`+V9VFiSVXf*Q4A4*2Mu zB{P_U;;JbA$O2-X6Fw}zMC~17gyW1{#bFy+*oj-OzdWBLVa`X=S}8I$p{W98uvj_# zc^K;}z{k(k#p~na>G)M{5R^K+eX-D9kW7oFZLfLp3%hd8)(qs*oh?BamRH}x?a;WV z{#tEqr2&)f!qd6MN1rCctvQ5Y&g7Z?R`%U;H3g_Vf}o67?Gd6HBNMY!Oxs^BGSpRB zAJqZI&hq|;c5YMZv51;5JhpUo{txwE5y)ddz8hV|7~ASkF3_!&5!)t>D%7jN?dSEa z!TGLH0&@ZNq$;U&-_V2lu7-9u?-kzm&OjZF@!?uTJPT_Jx)tIZEgzt<nrN)yFOUtX|lH`V(T4pLaRX@^X(z11NqJ$n5_@F>^;w#-s=@Z#gwolu_P-39XT*7Snt(Vdu>w&X{ zQr$;>Sl_PJ2_QW8ZEn8b8NEF3_U^p9fPLSee%?L_y!mc`6a9=-!w zP%-xn`uS|V_sjWqof5sj@A@ozUf?g?{H~gW$$doTS@+Fr_{FE^>*eC}#pn5=N){j3 zzLN=Bt67--ijs@xt*jzspq^x)#mm9#OT`SKWL~l=MTSE~ZA-0G#G6L1v=5l~y^$c4c^PyPxCZvXhgJ$u1faGsUp3M(ci<(OqHQ^?_`maf* z88t>3NEWOm?>alnA&MPG>{FqJ%5#;bqeY_27^DKpp7g)x6jui>ZbF?1g>-4Fxi(0y z-@amwHv1YRrfme(X*zM$dfCg>+`C&GtF=WLlFg+${|gDGrqLzBJlnQ zi#9C`P?O`i{anEgWu~J!_<;VktawT-N&n8x=r*t+`8vg_(iKiRfATD)3+tRx>Rbte zB$Ab(My!}g1f9*v(hF;M60WT`E+iKjLwylK(TsHZJvdJ~OJ)Wa2vsne$gfB<&4~9B z8<~QfNxELG_T3eVC8e%bnZNHRIa=ddsE3o2_s=bQHT}aeRJ`3}l{5|D-9=gcdR3)0 z#UdChtsXR*c2b}9wKYeWn!;^d+~cW7nJ|aS_pVn8JgI!^+jpQvRLVH*kVP?<=C4&v zg37FIw#R}MF;nAPKCXOx^EuJT*#vp-MH&HkGkkxpURH5-1v^(SrYM-!4{S+wh#KnS z3?#anLH&Wwkw^tM$arcIzyj)?+{(Bm_r^HH^#|Kid9)25A z0p8@%*k@eO%fFxkMb+nv@BS&B6o)A4RR` z6yJn|5nm(JuN1Uc=Y*bn|Lmm@-#)jB+fd79NwnJ3Kdo6+i3uVx$&Vk{V6W>cklnJwQ(&2?x3!}K?bS0o}8zO6?q`U|fr z(ssK?1uBq@8lXH;vrO1|Lc&f#6?n+_S5&?ag`{)?IpwU@0qF?9<4m=`Y(VmG5YL>>wEoW{Y-djM?l z4JeS_bU*W}Yo`_T-Gw%69lp{VbX61cYfL8aYd<_eWRafZbJ;+)usqjzRnv7S<}#ai zM5@Q(&t^s;^bc@l9W6r@n4}47A@W}%Ay38rT3NAXNRRv6XlA$xf3((-(~y$KE-X5^ z>PD&rjev9N!=&@=w^mM+m3L^sySYrUbxCeext0EWGnPE_gj*XLlYej4{P8C#1E@;D zqCE%Hd+GTQRZkNE2E<^Wg9}hYAEIB!8(K6Kh{0^VZ-Q&v>V!~Tqsx$kHy)1x^_zA4 zNGrC?|9W>^#+~B-1(>yQixGnXMlXGB>x0Jt#_l&kjn6mZ2yQ}g9POY+A7w*EY5X{! zR4N^tLO6Z$!Fsa&bc8|}AJP4FF|^M65tqFP>**xj{7=W)^xVnnd+|D(hc=zN?y2kC zMOT48V&P|(m5a<^Z}U_Zc1Kh})P>3BuGqxqPI8#8fR@{mSV07)4OI8LMR%ohNe8Ap zzKe2NMmh3W$9;X4tRph$+jqyev!fEo`lW+Srt}!h+6ENb?c-Krabv}sm(MlM@AM|3 z+K(-@UK(UAH-#AkT1H&2UNjXo9ok;Q4WAA~3b)|=-7Fxt?fkoXV51m;b`2(^RLojz zl7Z+iz(*tV*<|Xc^jMu`*swoSu{r)YGE15G8pJVu?UE)X1!Y?eEeTPhQly4P;DKCpgiZaKz@BPM z6T&p~I?q}C$6%R-`ebSOyVVufEdFIIL|L2Y%)jZElGd$OWt9v-q#q4HeNCi=qmbR{ zUNe&sY^sKylj+hQAUI5<}Oj*9i3at@WHO zA{egtjiJ_5qo`CJVeiSZsAAwM|m} z`FR&lr{bJPNm{J#OlU7AS-wk?S?_Sl9Vj42N{8+O$5`(Dbq6(~#4AhefT?6uW|~Sj zf2ttuG(!1dwL;7J#nD}&L<>unGo@03lnSYCGbWf2yfNLJnpO2WCAT{v@N=_<(Z2=w zdQrIog?~KNM6PMhDKwEL*VHy0xx)Yg6qAyNh02VPi`u(RBz4U^DOynxfO2$!d!x{;*;NMW zOjEoOr;cAL?w$A zrEa%Uyw7WfX?L*M4BBbThOgRF-i*-++Sv^9MjfUo{mxPLIt4or+s@3+I1cwd9qknt z6a6Ju9KlUMjiIlP>*I7B*NtC{_OCR6?qL>ovUJ&}g@8inFO2&FqUg}3G!zMd<9pZy zB`;X~IvthfcfGBjO94^9QM_f80%LhPDiDw8IciTgZD3xH)@^Bt*w7OFm!yF&lJiXe zhot!)-Rm#D${#s86G3YX$Q z2h@sCGp7u-EJ<0a!9jwi&j;zdy)X{f@@v3uDX+-9a#5)3!OxSaLa;8z7ev;z81$-= zR46S?NVHi8w5BKh_x+*3Z*(PIpGOaYJ9u$KE(@cICLMH#b^wc8UTUgvx26D*mH{HR zFv*b??2~3Jy#`Z}jExW-!cg>^qoDXHE;<643Hk*!wpGVCFHO z2N)qy6_}>KhentW#~a!9Zns)emu)qa`rDD4E5%SoQ;%!2C4!@zG=#mjX9WXm#*FU? z-B)-ML4q`@kjGc2?B+K_!v%_eSUlQh!(h4wCIkfCYjZ%+MMksmkzf`KL)$ZaMv{tg z5phkHXtmapb1QIKSFIqA&p61)Ls*NViM5KFR!-o-sT}5Z6zAVm=kvB#WEh$+WOu=T zThu>p0&OgfWmCvvu|KRKbUgMTZycEn=?}Qn!19DwhEAasouh;XoAD>8et-q+NQ!&> zDfhWeT4u{{e6!V{UQHy2jtM5dX%pecrfkq%i)`v`dA$)6a7!u zvOZ73VM#uh{Kp9A@0O+$IbGoY1Dv6bL7O`#xWlBc-sezM4p#MY7n8Oa9$5s14YU-I zS<7Jn{~?3b(rnF1?mcu5tag$Hqlndp| zKjF~?=i68c+8fY7QlGMo%GCoLm3-2OHgc0JdLm|d!HoL*Hb{0^G?FTh3v*RS4m_v9 z5X)7gVJFDd)rzK7L^*Gd`38hWF2+!*o8)`r{qZtx2=JHjiN71`>$9!y*%yDn@5AG} z>oe|)Q2+M!_S)y={`xuXFlqPYYZS3?s_sso@R`3pY4?U}?CZ--pDowX8qwM9>om4| zHgEX(N+AQ=*bpV8QCId-LK&ndvAaFgheO(Qxh@v zsK2pljJ{y|9tjQE(4eOtXKX_C5E9EWDAd(6|2Ivei|WQjwvz4kRD57~pG(lrca$(~N4#l@h!fG!@zq;)k)I?A*4x{;9Dp=imQ@jLhe} z6o?~qO1Rqk?{KMk53sNsQ*akxj|JI^-tE&B4WUqFSX$F)B3mFrLNE^mF&62>Z$&l@ z3RE+ZSd~}_rRYW?y#}MQB``Z-Z?8AvAKeD(e%necnqctvBNaa*^=Pg!%mx+^HeEc_)>Z4@MV zQSh0fjROd3@b4n7xM>mEmzFcCPIYRrtS)#hd2$iR8(s`{2`}DMvf-6dNn0P;#YAkh z(pLTWc2H!DkKWbI{+gZO*TcA8;OnF+EHas2zsPOUp?`baPJM)5XvB@b_nEjC4&G;-Ol@E`B~{a`NO6e5eoZ!eYv^#mUAK4)Z)-%`&JQ25 zAT<@nDTCY86t?6gLk;AQp)4sT-(@AK?Y21DK=r~CA2D#L$k?I9pRB;F?JhU3ldrMF%;au9K(PYOkvYt43E*tHSl!9zW6Q_e6 zpXYLqGQ8Un5eJBU_%|0A0Dnu%_Oxb)@}1m&k$K-#Y1 zwIx_xp+IX$g*tA`@NPVWVR)G>X^3b>k#)+tr;0CmSOYR3YW}I%-#6Gm%ccyqqDnTD z^3jl8Kc%#jS*%c=jN{CEmpy}3Kz_yg0~)nc#TL1PxWYu$g{gA%T;iAWelm)uE!!ur{>X}!cr=(iQm^V^|g`EzE)4A#;+ z1RS+m(N%7hG9riC44iC5L9D|oZmX;0_u7?o6NgSR#~I1>%(9~c$j~4GNaaxF4^k$g zHWK@JOPe}4TSe3Wd3T_6Rk`w?roB(hf?3Pm$3GTsd*52f?}&)K zh{DxBh)6a!01=4<`Ueq7jQsyWM6wb8K}72Q0}&}HQv@I)r{$mj4G}^5FGM8N4c6S8 zV&Nw_YY;o?bt|6cwrdrrgk%I#QE;CalnqQQ#_b>)v#H_|wqjmddN;)LtM|_;bhsSf@qVBNefH?G|fbA`#)cVK0WU0p8RjDOy+V+$1FR@ zdF(#gZri3>)T=J%`0E98s*B|C-e+ClPO^lrdd; zi20(EA|=D&-sUh40xD_fAxl?9*4sJ3 zmCAs=9?oh+_{J@vPwWpli%h4Q0r?SfC#t%!ozR65&#Mf&fDBx&c9rzfj~ix_9oo_ z^Bb$fFNGLMrO*->EdQdj8VfFa?OWkt+~+gfYI{Pnj1uyeDeHeRk$0u?yYW)xRR2Mg zS+Mm@y=9`IQzD%6E{@}mkzO)is}jg!01Wwh`iabi4lKx9uaCQXhO9HfJk51^+6VUC$K7E0u?jeb3M}NDKMU)D$lfUVgVutnes7~WiEW;><$&NrDl{)wTra!3L=_5gAL(o~Euw;6i^ zAm)Ep=W#`6fX4wM0GR+zIZbDP)PQ4HRx(FrmwO%x6T&90sfqjq;7Gcsb9cg~p{fdR z$Cf-f1yniR&Kj;w;6}BlK&Z$B53U5phu0+#d|_s(wQ=j|0! z!4oe->uUZo1``S8?Yfoc5>V7nkS2CKbG+OFOhde7liS1WI00jbm~tmat!xWal4=+l*+&cVm(QhE6hx@Et^Brz~mMLDIsfM9c9NA;4wTO+&0cW>;0_hK>K8)ZG zY}&G8&7{>{>z#ymisriV4;*4ZrXY)m;l;M@>jv)hv4W_?_e&Kzfds^Ta7@&JolF^_ z-U#Rop}rkOY&U5|#;}X5IsfB7;gEpq=4?mA^FnVaGaxiq_6dExk54<3#^y-0Uq64q zPY+6%$xPAKC{Qk;5`co|6T`@T9CN5Ab(*=wHx3Jl_8F3!|8PWmfSn`(7x4R|wYF{3 zWD7I+POT4MMCJ##0F201#XpQlLF_8AYCC`tDX;@DBB$NBMj>(B-tB%R&d`iAK6sHn zz$_lJO}~Vbs-$1VXa4dy6eg=Yc9<+poOw{y)7(AnyepuawWA0eFqAd&cTHNJ7nR84V${{s>U==%o} zf%q2^Q7#K)>Vdr&t3Bk8?`s9OdKNY_orzr!bekWpXU}wFG}Q^h%Qj)|AgOp~5>~BI z`}FOEw>-S9Bc5>7LQ{kE2a^@6v;JNFrpWsl+WaDxYR67c$OKp8V^W;yBM}2#1^j7A zx!1=uX(`Kus7f<5A_(4ZOK312x5Amy9J;uCMsjm@BOy7Ee6lfdoVO=vs69Gy|G_ER zKLlTrxalNiUAE`n57Qv?7ow%Lc3CeObxpwjT|{fxl`?`bYxGNnP9$e|qYsQA%8id= z24?qJ1=~8^TjB$hvr>DD8@5I>$9<4QyB|CLM_@j@7x`9^$@B6}k)t|kLLzuhi`7e$ zaK*CWp(E;wZ={Cg{!L@{Z}r6hElI4YXE4`P@Rgj-Qfc87TCt0*f&s!$*W+PxrTWTy zs~%G(u>5u+1_=gzUQFaLo8b$R8`^NrBl)=dIPHPyt;UTa6`s z2Si!|YYlNWiYJbiEDOnES22EPuGeVqNhV58+bkX9Hv|j}R4enatNom=^o+jma_vdv z>!VT&#c-z*C{dvS4|V6C1AdKMx{T#N`&lZPp%V1>w#JKDgCoGzmHhLtl-S9!qc)@b zTAmm8x%TXy8fqf*Oe=hFpWVsl?elc_1rVi0_Bwp^p7=a0rLMLelT1oZqDBu$YgK;# zi;I}j0B{l2{PIDtymF_WDiLyPxOIDen#4crTb#|OQb$BELdSb2J~Fo{=v`shWp4%4 zt6H7KxZwT-gQ}B7n)VZGm<44I&Q~NBxwbkVgdo;|nt_7Y-eB7?$|xzY5B?|yUvq^( zv?#>G_5>+T)FyBJDubn=5FwVC+qJPdAOfzvi=BrB##{MSAAus5LwM2 z&k!ce@a+n75NCl8aLuQb4t6#_34LctWtp}QBdG?M6DOOe=CUw1{`UH~eSA$vKpHk! zaX|*74AdGr1H(ujz_^7p6ME&+%!%AWn4bvshWt*^G-ad6G$sV3?ApS8m8O zf}@@VwIHsoj#+mb^ z4^hEV8*(;syK9IeggdR0CW$^7{9%B1cRYz77S^SGfnE3rc*O`ZypJ&V3|p1|rEeFw z;k6+x0NcJ6(f@*oZ3ak^Yq#XR^`HFxO39mTq@Dj%hX-l&y!4%Ojb3vpmFLoC-aUHhCUXI-G>xHF(E|8J9wdkS*k2{29*iwva zT|&-jI}6i6B&tG0|9VJ2;mfm!?R%cHt?TX^JrzyGe2HL;4~kM&G}Yb%68!kYvRxmc zeoV}6;fB@&Ejv7QN6o(<0_}W1pt%h*(3;92fPVf_9+=ijGOl)pAt0zw>W6Wvu-b>? zAz1Q@MjA~mx!-UHI$TJJ4HhKIqra*$e(y}Aj5<{*zMCaYpmzClOx~Y`3>OAPizKo( zXZ$#wUs}-(5%Q?zMfK7rEp9SJNnK`AiR=o`IJ;wXvBoc27hR+-T`(_^3_jRF8r(X5N>eLPC4+W6 z**FLt>Drs!e8YY742aQ6wT@c=c&!&Xz2{-@1Z^U9D4}HJ)VhGZd~z%ASXJs0*~3^r z(p#R62ADu zO$AiLP`sTXbY8VRh>j#py|*q$m3^3h-!Y8794Q;(EeFhGTY|sJ^ajt(KUmH0pqqAk z)db(>z%EGBiH%ALySPKqKF*-=GRfF6d7B~HDhG_oxvD+cWw&AGm|y#{fp_e6ua1hz zBa(yVg6jWrH7Ng`tFesPZP9nj*j%$I!JnghEdN(Im_lcrQVEuF4)}b*&qnUqs$8#fCTZ8Tur(}=s zhx1v4#)oJP^YzCD{aGjQ$iA)M^5@z3kO(32);h5Ty=(O^t(JD^)A`%7QNR<+>g45T z2+^;X8nLW&={b@ULyTbQrE};+mY=3&4DcCglpRo1JG>b+qpjV8{Ti~EZFpI=;lVim-qGf`}*eVsqemy2!^R!w+|d96Dp&T z#U1ivvBEkGOBeva@C70Z-wq1EX4HO3w^ep`qyz$|mWz4f>1{`ZMW#7>t8AASHkhTvcP#R%(v$6wH;UGO>#OR_FD zgm+FP`^c*4EVb*ZeU~{*?tT{xVwXcb6;GxUs!+1uL4=32(Bi6RR@WkQXii}2Ok$kd z8Rl;y$JJUO7Pbd&UX}VEc7@k^=3oq1_?LP?9sO_A3uAkUYVNy7zD-7{vr5Z1G{jkoIjuBcU3Z~CN zAvF(v@=&EZ@Uj;992y);jj*f~hfR7+fjW|njK+lMpblY>R-Fa)ScJxl9)e|r0g{Pd z)~LH45Lg$oE)wk^G0-X^20J)qXttW(irKY^w)FiIGmB`e7L|zgV56hJYRHij6htd# zo*(D@dcxY3xCuXz>q1HT6^VutCHpZ4e$L_$WnO%l3>N?K8dH}-wE>7uO?;uDM_*F1 zs=X)f0B^ay+vEg2JJmZM;SWASYi}Q7{u9@mCq^d0+%}0m!sUXi+9$&orNE;BLmw2q

&lH6+P|?@-^N-zq#;RzrV72N{j3NDP4oWQ4dBY4j@*1nX3-mN z`1WBODEwq~)w*TyOl!L2QVMC6?1HLo^-&+)k6TVyR3^C`ktWSrrE|Sik0AI){FbT{ z+#9I3QrpfvHYh3WLgbJcogtW!`m+qTwN92mJa!)C-S0cabxnS(K(_VEcaP0=MS zwf<|qp z@7CLzUGAf~l&n56dR^}tm4;v@pBBGo7>jI>R-}{FVN=#Yv)@H+YH$C8wRZ{JAv zsxDe#W%xvF8{}ft&n=?KqeF?$9d+xMZU*^>&9IhLcG`^vle2HU9C0~F=;*ofR_+S3 zI;rvf2b&2H{)f%PTKor_=`76RX8gfs(3Z&;<{WDOVKdt6V;Ya`|G{RuFaLwhIDvNp zN=X-uxA?g_Ay-;0_GUSa_OG!ykY`jNZuR`(eiccUg9((WH!dB_O(W!XDaD=0zOZ@m zpGAQ-HXAS_UZm~jg3cFlJXe8BTpP`t+%#QQq~9FF=sUf2mkviA-Q8fGiT16!g)Q`~ z3j2+eKzoHa1d0TGKJ7Fp$qm343kQf$s7-Wy#*eUI8S{7sqbR^N02?bUqtasf_dVbX z$8O{W!$L3!g(na58(y+b=-1vc|BQI4i4epY)ba}RxJu*5tQh3@?^3VeYs;8%f=vS; zvG>4*m-dXwO)JJZQqXWXfP?cJdm0r`$n4R6e@uP%sj4_*74p-E`B~hWP>8N$Z`xhw z0O1$#S2E(J0?+4poZ_D3b=MW+AY7hc4@H23}Jujya3U=!XO~kpT%M3Fz z0@*pJdyrwIRc&It{QyG4%EDQ}n9BD95-oKdOL$FH9EN0+bVd$~d5=z$P(w%$!`gUJ z_D+^V*b^W;p)#^C?P<4sv zw!=}KIGZS2r%=(1C_j)5^UZwwua!`4iSQkcNZ#YFu;ZF4*4zAFoA6CfYx(#sY73l* zB^I>zp7P6m|3leWEx7)v95Jw~)g)p>W=l$j+{V%nm*fak;)lwA&KlEr0kO}?ljx?N z@yOjzuk7A`>Gi>#_&LU-O6h;(4&h@;$o1tgIFQR(koIL&OQ0w}UV+ZswA(N5i8gLu z>+>x(>lf=oNm0Q_>My+0h=t6s&*P=c749g&6#fzQ93G1vbgC!}k#dvPbEVr%SKLy? zs_~Q4RNzzKJj1*%BtA<3+RCVlri7YjIRGXX%)R3dHr1YIeP1rQ+exDojCE>Guc&mRQxXe`ijQ05fX9kRX?FT4#?Em(W`4rvicI)%dIgGz9tgs8NtddI9IlI zZUHvAJ~&+eQhxu?H~n$=Y1<^0?ZXkK!zZk-2h)abMqgv&b~6_T7o?oR}D*ZmA&C z2`w5UFr^~51mz{XIPn&CZjCe??a|O?4d+c;6X)ahV>2+zFw~FhD(;peo6E=5rxAbt zFx;1$X^2k8T@6)EL>z3o?uw+i!cnuu6eyJ)@YtVg&B9T=C{CNw7r%r-}dMv0>z zy?BNnJ>q2K;GB!WlobYCbu3aB6k3y_?(KX;Jy4U?HE(*NO{5p^-dQn_4LI@v*925~ zrX}nailuE$80MJx-*jIFXy(qEEHiFoBq}_yRjT#4<;Pgd?z~7(VD;-zwwnj*`Rd@( zVVnoa!WbHLlRRAM6m=6^OWx+j!r%N=}u7`2&! zHUImAQhA_kJ!#rJP2+3cLAYrewuvxZYF{tt__S0wrc^Z4woW|h(<+IfQX**gjKp3M zO_J|6MIc`Q2pSKzu=K^1*2=g@K^4%=H2OB)pyAuw373Vw5=Gk%<**#jYOXe0GbPlq zx)>vhm8gKceF?-e%!q)MzgV7q+~SR~yyUU2omCr-eDnpRI0=EWWFKtvZB9z?&%fY; zI|p?+FdmYbr9Yhuumlp>DSnj|oMP!v6ey0epjat#vQ!`Y5$9v8V{D?yu~tT$lEsp8 zi(4`J>nX*AC*W8r`6xoociAy}($F~hSPEIaI(3MC(=bD|lpT;=TY7T@yHmH~5TpES z%a4HXSI5ie)GnXwR^%w8^pU+ZoB#y_tR9MEyIx?t!i{eVU1cYF_U3gXk+;yPWt(&X zZcp7QZsZYyrUJ8>Vngw-AhjnXX%M+q05#u_s{|WQooykZT&*X2HDoHL1G7r z%IY7`M4#X>bM2_$fSX?QrUzGWUP--+4q!Q+m4wp5$17e0pCDBrb4@d?J?#&P zKLlpDfHexM)i82AGpk`?E?HVaCY?A@5*74?NvwjD|hM;dNyM4@&w#( z^5u4;x1GZX+n(2R-5h1$PJm0$4ao(7m^bBK<&oe}t;u>fUshxQ>#E6Swxim&0DDEn zh6GWsMI0^*UF9(WTQ$xtg8k^h5<_2xtn7rE#yVOmm<7L1f^P!$1AINR&noMNnr1RN z^jI>>?VM=t{Fj+z^EE_T;HOlmTIa1r=Q&QW~c+U ze{?uMIjLUn9PsAXA7#!PPwl(*k6~w^rs@yQKf6x*Ps`)~2z6}Q{@0u5%8y6qr+Wqq zPx6h2;h%?R1_(s#r`Pi*`ky}M;AgUb*Mk2e>iOabxA`BX&d=mO`KX`HKai!VN8kE} zX}3nJSVeAESooIgG?aQ95E_d__eK*)Hq*rYLt*TBulJ?|eJUi|FYr8;c;c9EU?5`M zCO#2MWP%@rxVwF>`;nuy$dNEOk=yM8X7Wavr-*G3ux@^yr>Z2BY7c_VlL5!9!zS)`4sh}REo+}=DAqUlcb=|rl5y?(o-AwXrB#xq7P z&;OPaV?Z-GQQM*FIRQ6;0k#g_rv4WXitAqb0w{7E2>7C+dQ|%l8-!}~KWtDm=Oj~F zu7Hwi+~*2Mwzqh8O0WzQ8&OFrA&E$HV~05NJ}|z`E4E?n8Zd)K06m+9P%S|!>`)-D zu>wPXpuA*w2s=dB(@E$fgKc691~9&5g~q5;R z;obDnOl-?u^`_wAG*jxMuzlcIPjNyKn(?*pN~}}uIz2qd{(B-rPGqp@`@fa}di2rd zX(Xj}4Hn+R?iE z`zhFx9on@TqFQ(C1tJAPx%;AIs7pIHxkFZ2wa;)Xvq%ats$uvG?`F%@J~v{S8lD&* z6ERCBuddGQN}f&IFjY!vJ7@{!j5}G?O9-pT@HUDb-3T^r;o79N?}1ZF9Mt3W2(0d4x_~|!a2w6__P&mmb$h>v-q*xA@GG6)v*Zi zK|2_!Z875%Cv`D5Tz;n-p>RIbZ9QJ^0g6KeaovbgCF3oE$P0krfb}XhS1z^02{ohs zS)idrWuG9Xgy}F3yeM_7k9hNA)j84?HS$k8p)UG5s-IM#pqGbQSyW>W#ni&vq0xJ+ z?j9V8W9cIMI%y?YX2nwd5@96sp>%T z29{WSXXPy%fyort!p%G>bDeNOU0kbxeB9P;cz)o{@%^45wODqgd+7!vi{X5a#6=SJ zr9G+DPfMEPv#;XUK$3Q;BOjTit4EUt z$=*PSJD01+kwdv_R>dsF(q~u~i6KZBNhDckHD?gSlC2CR&nZh!W4nlS2(JL5(iru_z;LA_OZo;0l8Q$M%s8Lt z#Tr_BC}XQW4JB^fOKrp74THDbK*8jgS+$dZGKj<7-N5+V&?;k<9rd`!Oopi{N09m< zzDQ1f0`2+0YJXU{{IuUuPUM;q9*vUVRBTJ<0Rx|#=LH%_;@lZk=F+pW#>m*MP??2C zhQT1XMg!ialtdtl7II^6)Qi4R$7u9;D*`5C6rkzX$T#6-)p4BU6Y_!@8j#INkkbX& zGh8&ID{VR!{R>zOLgo9n^CKbuZ)A!FTYe=a)duSM6~?4O^`+K9!*fkcHR03xB+ih0 z6l4bz%Hjw(UoE(8CK^&J53~*XcR&2u%pcz-+1gT3uuJps%w)^@`(fYr=#JxyO=B3m ze1k9uLE#-9w*5;bfJ*|@euDzyhwz96W5i`M%=D$abePvuo+$Mh>bnX8|6HRLx97|P z(MxT&fsW7mUDAqyPV`#V3(t_HTHT%*--&`HT9?T>OX6cwoF&VTu+6#Ph_q-}+;n4B z-B&Wnks3QQ`BoeKN+muwDisNnrYLfof=LJIn8czVOtFI^{aK07^6`CJ2WKe+O#Mp1 z7UTbgOl4J(hNRCt_^;m!ald=_i=go<>XAVs*L&}fil>5B=2TmM=J{9=+a{qqW`Cl+Riyr_^pnHB zpLr*CpaRPE)$3vFo+WOLG!C}^BarHQ;ae|}OvSx|Y27(a@(AsRifKY9GCH9Ic0!lv*UfTOfyAW8!` zk}6$Or8JDVFK~)u4+>a!J*xK(SSh2GkTYk>z5oFVv^g|p$~eCGuO-$TQRz6XZ_yYI zkhfB7qtf4BV+`qZA!~AmtP;hU+DFIRKQ^5EAM4G}(TwNekLl*$(pmlK$9SWfwEyG9 z8L0V9Z?o|{zV7wY_oKS`LF)ghcABecJb!dN0;)g0ozH*K|0Fp-i)S78^Pi?`{h!B= z9p|}HGc>kaHTz%8OujtO>CeFP|9&Q2>&LruyqEaX^b`4S`TU=VAFa_MK&ziC16QUpsb@QfF~%)REXG?EF@+uGU(`=CG`28jc8 zWVDlDL2rmew1AO5B7P^^4b$FT*wk&5k314{8gdx7rw~LYZ6b3|!_*1v3pI(24+x+_ z0KRcRZS|Jxnv#|bUz8XHKB109H^D^cj+APf3nsw?H;1(yJTStbUqDBX!=UCOs2!ne}}4qR7_5Z_7-MB3^!2EDi)Cm8J zn~LNWTiqkb-)2Z?koJD)c7wcyU9ZfjhUjiYOPjDyO(`V~p`g*U1TZAY;flKd&#S8AUX?55WSs}phs8=$}*LcE1Ix83@ zfQu)<6e;uSDy=U_IFu*0DlNYlArPJoxtvzs5}b(zScpml zOJ-X+%X1Cu5TM68^+Q=y*7MA{FVb3x&T~#iv6t?War}V;ZUf+6jLp3zPW>sj!9Pf4 z57Tfsh>-#7%)5A`9W^faN#aCdi8Lpb$_<&Q5>;^6DHgRR2p@Q7>3!NXRaCS5S%i_% z9zgF~Ho5CM^Q3ta$wbayMLRp59d~=olxmB@ty@0WJa1aDDFrF?*%5^S^jdLBrUD9t zz8(vj%4YuC=wPa@^cT@YfqdO2?nSH#MTo$k|0Ah?1$*A3;I!wPp!HzsHW8`Ur+H zOqGlg96Nj462#3RkfEy!N7EQU7;X|GhpO&+*4|HVZ~$Q6tJQ)selRKIvHt@mRjWwS zAzrU=KV)c+l;Y_-iCuLsf$JA8XG!_Fqp=+e){4fkx=6^%5be*soKR8kf5WLeXD1!x z7tR!O9*D$b3|}*%81mdo$Y6qZ2zh2SJ;&rY^_llp%8GBMJR-x7ojq?(;X)9+gCm^& zew;)fwey{;Dhg7t5Y0-Ubj~zF?2ijpym9ikV$E{oNsouYx&qXjUJWdx0yN5XCf`2x z@7ni-H3xXApP6Q_y~Itt45t%ie)JYPcDC>$;I&^r>hWPVMfA&hY{w=nDC&}-zv^8-`+fIbu{(c7ow3nsa>S;wyG@CzLAl8}Aiv+8;lo0jm^qfP*N{|g(EEabzn5uQADCVC-@0HCQdNyw z=iZ!^=sVn>JvX}k$o7EVa?1U^df@mvK7FD1I`*_KJNT;QYVuhBvwj^8Ew}BmjKU4> zy?0!|iTW$n`TRYZi&335i&J@0Ik_QI3!SCS87(hzJ&S#VQ&AhO+uj$9JvdEi{c0e` zw}YIK?{SiBZtGL3ihiprdu4<5+-F8K>iEj}+gjT8`kif?=F$hhxqa=q6*u`opA`|S z;imYi8ce4AXu8Z~_$wU9PLfeh)lYg-tg2F}3VRQX zFvM@-bk1R*bmP7egrB(9henY+C~Krb+L^e(X&(~4H(s5KKrX|v@}g3 z3BJpNqmmNx03w%lZCy3gcE}=wXiAM_YM>+>B|Y6{bP=SbVXv6Zp>D0@wr&W@_aH%vLo7^uy<`nnsKP7&cmjxcNTB>+;l z@tvX|PkB$HrW(J;1>v=)waovrR$7AtOReRSPiicR>mxE_cCjV5 zmzlAINMQYRCmi*S{~q(~-1q%SQ*Mh_9Bx_`E@nGB^6mlB{O&9bm7~7 z)py}QW`ZDNGVr@)z*4!VxN7hn(9-9`o$xms6L&o zfBeU&E_0l#uuZ#+E3?pB+g384E85VID1nUwf4-Dc{8`&ky7NKE@Q`qa%3j{eUHA2 zrqZ(;VE);qJ;T~lAl13pNf0p&HyovN zxfSh-la1?n!DIo|t|Nx4eDo&8Kko>k@pK(8NW7LMsa&6BQjU~-!uN9CLeH-Wb&cKs zo?a>eKQhW9I8q7pXL|p02lDC?4!tp8Lr1Nc|6a6uQB*DUh$2;=b#o$w9nun5udJ&j zfv3@@giP9-;fZKsu zTh8QzsytI^;wb!eQ@zY3ctldbG5dv{XVUAtF{x9D&&4j`o`*gv>j=0a{TCBoI2u!Q zMgw+wsug5(`J1#!wGn3qvc%3d`ptZ3CYGh7;EbbcwLf;^cG1o^oq96~&f8UBs<`(` zsmI4kdEM_tqyn^FwKGXPj`^?Tv4TywwLhpY54!}}zxQ%r|N2_5m?)AgdeAmcQBM}! z*w?oY>y;}3(44rsdAZ!aXAJmecfRhmk#I~b4fZx5=<8_b)Q%ceT&^B%znV#NSO67E z^W}SRA1unN;yyVY)^Zc~jpBceoS!}i}5uelHAppc<=Karow|u07C6&HtBR$)pbm< zj*iOT@UEUHAFMCax$HGG`!=8@r8Mb=8T}`Y6M%$E?pp&FSY$a%#fmY;a@$yL3UT@)UIz=v}7P?&l7@6_2GUFmUtGN>XaJEO;<4X2lM zi81dFs#nTB7-M5F$hW~0PQ**w<=k;hZMY~kq(M?KZ3*}obOpzxSWm-)U)FL}^>*W~ z6Gm72_Sb*azi*6cD@P+q@_bw}SQ(mOuS8;ZeS^s^L1d*bD{{)Lext0%6j=eeiYnXi zoY+e@=?_fVxE^c1b!4%hi{b+vm##1{@oc#W$z{#24Ol%2G4`FS>?YSn~0yO!RlC8A-P3NyskL_7Tf z1W%-xN~X@pn#_>!r>5@YC@2OiAw? zr{(IEn8e&P>r7_a;jqkzEb_>R%$oC;bdF+ZAW5XSA1Oa~`l;9RcmEaugq&(bqj8CW zE=#c(!U_P}(xEkODeBln|gFGCX9P0n8EI1-RJXtI&oJKOAHeG$guMaHyJ9 zAH&t$gXGzmF2n0fSi=zcn?c7oG?8IO<*qzOehnAgE}Mo%7}`ou{O0qP#nF>JJt%-E zRKrdiX=Fv6o$BJX9=NlPS56xJ*SSnFdby0076k3*snxI)?McO&8U~g(NiPXT-d##e zeV|BANO;hWp+pbMgqyFip9Obx)oaW;SLc zt^FMV?=vyhiz06dCH@RnBEv-I7f7WTl}WR!kON)cvy3x_i2MLh24O%4T7Fm&7L?_c zeO#&Q^3Hk?YZIkq8^J-hb>?+Gh0k%*9fp%bWCTh%0!Rls zcyGe_R|Z*>=5U|{)B=dCbF%16y={*p!kQZv94S_PI3Tjw*k z^`s9y`@zAybJspgSa3$E^J;)Md@DvHxxmf5L&G(+zWo{feLe<`?xqk0TxDEa&QsY? z&%Suhlv-I0y7UHjsV|Q(zevj^B+#C66yV;`>O^P&dhHV}CxFdV+Do7|0_7#MFq4LK=2hvymzd1d7T;Nd2Kb&hz zt7Y;8j%8{Mc+TKXJFj-!`qDK3rb~{`X_A!+nR4FK)1>9L0#-NZe@dZMAo#lg0_EtgdbAj$28N_~3vMGHb&0!>+S@nEkG5foZX-Pf?%6 zU`=(zJ1?!Mk};pdVJ!svT@dW}%oxoz4RXE1PzQ@-em_e~WZ0l)m1PbkT3Ryndp!|( zFt9GfWRocm6UBPPC0pFFIzt*voOa;>?FzIk4TV~JVoiR_E?kp2%X?k~F8#h`8U=QH z2?+{yG1LQvYm~vNIM-v1oOA+#WaO&BQmF_o|3R_EV6#M9&Tf-Q4Aam^TPto0oBb)< z`{-lS^BHH*^#vx)T4)d-`ul1(^>ZOV?mRtWAz(r{@jmS@1s4}^q9JIbkskEZ0r8)z zx?ZcaUU3*X7Tfov2js3Cw`mZDBqWD z$jdX}m#f}71$D14$OOVv5VY2%$YJ-Lu^Tk2mG-3I5h10sd4gJZeFQ&3cIfw;G)(P4 zIzHIP87ZIr0$2V@+FCVl)4trTqK0o7aRN{$OiW-$eL z*t>v+$FJC~CUTCjm;-L~z98tzm3H0^0wi58bvBtRql(2 zdx){!(!m{x>dy--Q&j}(0e7ahSv8|NWaZS7^P~u(B)m@uL!rP|m#iCJ;&u4?icX zQ*V?X;c@eE$1!M(0B z@yn@r{ROgUf@-#KZhT`ThC8^e?^u#;S0aTOJf9DaOTUWzE6$RQ*!TPC!T0NVszY_e z_UrlbwxTB|E63-Z*9$7Rm%6nOtt*&<(p5^>RhZMrV`hnBHe^ej_P_V zQJ-qFV5Z(6sbfyXYx=7t-4Nf~&zJKXdb%w9(Wm9ScJW}}y2Xo7Z!>*@JFW5xRMT5r z8U%p7t3L-^VEo*Iv?y6IG6N$8 zs32lcp%Kddsx5YPG%LG~Apy#&lUzWz=*hOm>?k^xpXJ!K#TFpPyH1N5SI!2Knhv`#qYTl?p zu{~g^YTZ7#Dq|_6uMzLdy7&yR%~4H=;EQWQPT^&2_M9q(l~et*NMo!dC2|h{qzVzx ziN>=7;}UH4l(GyxAe0=(b4QfSrC~fK#@^rXwQ4@z#3`=6Ram$YhKKN#iCt8Wk;xKPXlYOe1Ma@nS za-&5djmZ=m>Tl+$D~&_T-T~Fw3607xTv5aNI!MVD^2i=d+ANAYTzV(QfqsNO#@8z# zC(Y>n8rZz|>yVugG;v_+ppp=sS5=_U2C_6$jPzB{5WpNM>m*$O^B807#~ig_8Y-u~ zA<7e{%wwTsGfk3VbpqAOeCDEk-{ADon-nu6dll~2 zCgkrjCf8{cs8n-$PO6ZLJyn#Xgy=RRe-xHzHg;N4Vd>H_lwp&*UEdKR16p~@6d#2G(bW)-~Y!y9XCwvq>p;I#g--fiV^)}B{dkrbV&uY=GtoF z_^d*Dlu$<#9B*$CrbUPA15C|2RoN^`usjBc2dg&kEsb|&S0CZ5ip4aM=pLba87@6H^!MRFfe>`02JbiUB+_}Qm6+l>4e9m8Bk3tJ z9zsrP@<@K|NxI^iskQ*siFwissfZ?!-)y03xZwaRczBkapwef$TVS8I3UWF?{Be)C zAwBBXk}Hws`qRzAp!%us#u~Ozc-{`ss4=jz4@WUutQn7Qj*>O5WFAe192!<%2*HA~ zyf0O*Kk3Pefo5p85tEQ+E!D>Z?+y`jVWt%47dDF-amh8P)5qHq2996Aik}N-n|HyS zD838yoG4)}gv>0G2zjWcs91~*r%sVl$`UqRC=OTOP z=W4xw;V-7XMVJ{3k}^aVRYF=efo;=h4-t^p##d;Pt~cvYEFM~&yAxJdDN3|RyElSX z0Xj-p;yKu%WkX4QW9ZaVV3NWMxddIGS{kVV>CiV(FVb3lE27glE#W*L_str0EXxAC zAvYBmDY!tMspzb3kyZHR0w78!M#aWEh{n(%!a_@qKw~Wpe>IqHB1{FWRFiG}>!f>g1wpRs4$A$+&lN$JMF(vB3PeGt*hPO4VRaq8#reMy2gNi=B zBE7-kw}-F{JZzw1Qg?q-2Uv=8;5Gxev&i~zuh)wSQ+gdNdlX(DrPX-z`vo^fk{*Ql zKj=^2x@+IQB0hvY2o3^tVlTe;e0R{87(^i2-m@{7s!Db1)u0@rwdQ)LVUw6nj}za> zDqKhDV){8=_7K`!L@jzbGpDR;#nH&xvy)yQHx+#m#6%(=FR&?o>js`~FMDPj%ZK#n zPMl}74*}trEL~n*9YsDgCM`}!=$+i`MJ9%9oEef~f# z!0E6!IG5sT+vpJRmiz9+HTn@2@mU_BSApaas#mV!;0E!w)aBibJ?9zN%OiT#8=J6= zLLT@*HoXH{;76;18NI7%oyXy&-y zO~&7V?I;T~kgX&WuW=xV8uI)#t3d+0ZVr*qYX11n2|lz%+5m(AKnc&}hoN<5crDo2 zQ(JJ%v$E%_ZUSQ3mzMnoZ6vO1ZV~WqygL&n{>TS;8}*8 zMHm+)YBjOH+r8xct*%l%w=?+~fz+ltOLGJL2n!P$d$>NrVMgzX8?Zp=s0mEm5(QYX zQ9vISAY_A?%46gr)t7hzuZY|{*Dh2}wieY1jK-r!01BAbo8?^Yr8sgdnK`hF?~*sx zD6G{S*p?YCMw#zJbQODNcqE&N0!@otuqjiYT=mm(0AD*$>b=6|;>;BmE8Sj?V;2KO zWb=UqFmI1w8V6F&HEy{`Kq5=BW2!80B6{e2Gbeh%+e2#8t<(-BO`uZy>T3y~7ll>y+bOA= zuUmjnLA0n@;NwV|CZsj!N)a}-L{FanwybJ1+XP@!E3Qf=@wva(O%T`+2JiFerY#ZH zW#;(SJNhff3ev9TJWQ6KD_uWK=Axq>I3;a{CZQ-wv`xWxMVLdj|5qo`3&ZrH! z*It*`W5DHZt32FlWfdNMgkS=-Xye(S|1JChN(|SwBw(ez`Ie?rc>C)iJ8k}Y9ed+Q zmo{ryANN9C3CHNvizGy6PI~7=uxBwi>rI?0VY;2CIt_Wwxi3^UEB~KxI0PPl01QwdBIakudKihKK)Dj!+su%M=w;d+&T5AImzuoyxe{a>7*~Lc!^qF*Jt(yzV%3YWD{cbfvXnvVKMydvw zdNaj8X}ZVUb5O~sgd3U7^HC+aENadlY{ zo!6qLrpqZ4?qRw0U&8g)en#wiRuBjCWW}#LQ3E}L#a1^MSk8{v2OQ}^oU_Cx!WxbK zi=bfFq0beKG^c^Q4LO@+f85dQMz;wa6i_Gwi!x}6<0U0s84G(s&44ho_(w}Q%wnnE zg!|+0F&N{w%I71grV?tH)3kKW3mzNMXwjOmrpgF@%G<;tS65rE7zOr*B~X;n16rS( z$7Yf#qG(sauJ!pjx2S&o*`f;G1Xt6zXI{?+y{HB zq0lHxDIEEAy8ZZ8_-tM|`5lM{%#snb$HtV6(NM2~dmHp>Ah$`ce)qLG){#OmQ8H)d zEiz^kDK$2(u++p3#Kiw1MRcE^$O(@Wt3P4g04#=%XqUUvZ*XG7`+Bqy4`mZ7jW)lU zDh7iRDoJ2>h|e@J(oB?Ft<xPvc7v$}+aQ`#O4NnkMcB5-Ib)Wl zK4`fv{Fy0_qV*^D>(_OhP^AFCp6IZa0GDnVN`O;zb3C0m_^{jD8iA~zfU=XV2R(hFg%+U)WF3L9X7s_dHcQq@72!H8G1M9T6G=I@x;6-@`Ox0!MyQ6dXkpV#DcqLemSnbKkk zcfyi*XM2Xg@{mGW)mLlD-LwmxH%96culMrxqeu7@Q|{O-Bn}<jRAj092NfXdViS zH>m4`4X?0F$-cLP_}N5^E0gb6@3BYibKOPN^MY+@1M)z-C{Ch4{%5&dr8}Nb7*ev6S{Cb>ln7S(JDKnoQ8}g(KROe_Mgd3Cdu!6VIj4!4LJ+y#%!= z{S9-+k>QWu&*>xL6E5hu;hV)CXXe_&Tqc;oh0S7#DTDfZm}TE1Bce&)9Q>%C+eygD z(!<-qTKQ!L;f0SESbhn+`|OZ)(}B#1di4I7%x`{QpI~mDcLBn;l3$S1_7bS~NDD%- z!mZi8trFOt6P4iOgB?OpSeSJxGpfvfYy_*Th2?8eII}<9Uf;Qanic#!<+E1Y3Z_%F zTBF;y`FE)4Xfz-MWrIxfx*>T$N{tb>CB}+*eDk+h};tyX-JieX>nWP($U zWZ$s(RYiD(v0$=jM$KzwG(eBzLcHD^%>HbK)z}f`Vy2P51 z4c^()URrDTRe_MO>{O>#1E&8RqMG#Nj)8LFZ2JX8)m$ldi&B8FH=wyXGy z6sykAvnRHN_Qzd&QJt~}6hp(hVYWG!U6z$K{FuP2s&Y0bdG%7*c%rn7&c9aXABWD9HN@ zRne_KapZquyh#52e75PXT|oGSs^rMmiGhCbitqE>LCCpFYUE^pRJYny7L*J_{mc)G zN^Wlte{FW3;P@-eA_LJ9&1e`oYRqtS3Fm=ZFkCGbkNQ*K_>E+LIWlsQy{Iz0eUcc> z%sz~1MU7WA{FEH8d2M_Fr^?!_jIeg?VX1vVU!YAk*dL-70(fEFL*Z`R5mnW(km8Wf z4w9eFp*NdQ6~koC1PXkMHbvIDZ*|i;!iX6jJlWp(7vPYOidWk(6I+GSu1DG6#(HyY zxN!;^$ik9p<$CWOKr>vl_mcb=GEsPoij-751@yFW2FFd^WrpGM+|#YLNvM_PCDEYr zlIPyWPD}v(R-3)VHQ_d<+gEqLEeQ-l}aV2A+9%0e{ofqZ*FS#^_F#hY< zp|M1%u=zr%Ut*>2BEh7H@T{VOIX?L#I4K;*2lf!8Zew8<8RpNB|3yC#5dIa}BXGI{ zj~0kmaW<7I_JmXgl=W|+2Ev^m_cV0q(#g8h&;_6y_3R3Ra-k7&K~$2!>@S*x`i6tx zD`W`^)5Y?Qn7T#kpX1{!j=-Q>Z}ZlG@?1ASWeGAIDe1n2++-+0MVO$Yjj6m0DWKfH zDjb!C3BdBj7x`GmTGBOK&S5kb7=MtCiIkH)L{X5#HCMb)T3SI8L78E%F6|V>MuWi_ ze4gjsH{mraLF984p9D~5KLbtD>hG#XIP6W~B}%LPAgiHl&?3)y19u4S@BDb6!HWYN z1{7LD04CSEb|?eWI9g9!AcE>$zj=6{XFd;<77z+hY~TolptZ4+f~K6oqqt+20?n@` zK_fr8m(U{evCnN9{`YkqOy#jcn%U7*=7s z++A5$E^z}r!S$VZ$-s9pxgdlJw?n(spsVs;Om_{r%G9YO_NKhHf^T9nT6CQK`*+;v zMvZg+@SP#PB={xMHVSqc1nVAG=qG77NrB^C2^OQR1MssW@aJB~0R~C3gPwNgLIQss z4duvWg3zJ^oSGpbs6p^&MX*))J2ewcDqHecYg(wF45@4i%8ex+qI|us#r58Z7Vww_ zlkTXcQ4@`PQp`2E-sdk*ukyFwDPQaO8$A0q4yfF{jj69mctGogY`0 zap=;)aCmUwyt{VYS9(176Ja8esRQsG^HOOL_iA%n*q7XWD-3^vw!4_>*1W})Bz%1j zLQE~X_`-*lM82N2m0{fPiext`7@^jp#;z)hPORM(yg4sO47x2|+RloL&o4ZWhkQ-Xwv2y&P zt3#P5Si4qt48q7+{R)tZ&!CHa4c zAAkGH;OK9Mhd(?Y{Q1Y<9)29cKfXBn+tDxXkKZ009UlJh?b~nOU!4BPkAC?Q8?DWSC8#y}q+kdw1Iu)~bEmkrSspK=`^jPYzl_yOkvy#PXGrBbW@lPKZWlDp#DmkFG&$UQ-26y zvPQTj9J+R_QJY_`{K#s12Ba)I^;1=#q}Z=mQCp57vLe9iaga1~3svweUa1aw!VkO> zHlT3l%kIfZA1!5$t|X04l55|B_v{xDBIXP5}kyE!M@RutTDAAx;#<6v_?xU?gVD8i$ z*heg&OkjGx@S{h5x)%3ImJs*mkbsy-We^y1d~v2iHP@mkVoUHtCdDMIe^;+e!|MgW zV&3qyq8V~|+nHBaXZSjwO!eTFfe{oB!+OuSkMg;ITdv?#(AL<724#Srq%)|$Yhyg4 zm>gHF9-CN1ap>N$$4NAj5m<>0iD9MA_YFWFYv>JsTh{=PAQx{B6udKe_NHDY?^#}C zRCg0$()&KJf(JfivmL2O2Q)J)^5VN!Ho*-ySQN$fzJ@AwDAh(-TDY~Kq}qt3z>Msd z!BlZ85GvUGaq-=&KH)<)bbt9r9XHf+f_V-;kp|W?bS1O_hwuLM7t=}e>t6?d2_TLB z`jcUOq3L_pP2!Zt@%ax4h@#1)jE!Lb54sEuKFXPRl&P}o-+ z0ti;qw=aa$U-;>F@rj6MPUwx~DX9QH%j`e_2JRZca5N)1SDIe4A-OVVRv2i2)Dr~2 zXjn=rp?LTQ6z3@fZrwu@P9f22za7`Q*JHAB8W6 z+ppadW=K5SiYJn8?BVS#;R6sTb{NB*Gfh*fX=icVZ>b0Ww6Ptq9DSiCxQ)#oVt?v=Tvq4s)Stf67!8+F(vMiR8v;wiOW@&AFVs%792Fr_!!TUBex zbl@@D;By1`+~7r9`*r)^MR&CfVvIY~fy2VE)~inZ35{Y(zFm9%+5in76l2qB88=+> zCHW$fxU6LBwP8$VI&|vs&`!Lo>J>kJ)MyMuy~SFiOPccHw-J>Aj^C%Mn#EkoEOQX< zs3A8(oB%!uohE&6hVb&fV7FedqYA5*I+s0|N?hF8qV|S>fe*hQiy3zQBp@yt7|6tY z%IE-sjxr;K1QX!D(>T(!44%4VV`~`*Z*BH2o`=zk!#YaRipfExOiT6XkvOWT(OOin zXHgGYh8}bne9&F^0n~=!V*8llx|uBy!<$!kQ4A2s2~k{KxPv3Mb9`|I4Lc2U0)IHk z!}~Qy%zNDQ(mTnf|h!Q zMwWi`HJ`)T0XaJLWVbRVY~A21;j4a^ zlS3f|?tFaq2;*~?SfJq%f0~DOiGb5MF@cNJOgkKVV6jkDk}&3NTp_M~&6#YMbE=am zQ$$IqkE%4yvf8#}2_-?&ad!Sd0E)8Ft(mRJsI}#cE0JIX7}v8988s62K%rJ>a^hpO zE(eOSCnm7g88XwU!yX4+%@zSPd~`&U>swl;3KH$9=7`1EN2wzeBE-Q#=&0qQDc^)0 zIShI|C-)qAc}Fpi(pPtk&`QgkYMy{8ijM>DLhjKmyptGD0XSFe!0kF%ECDU(c+gij z%*Fi*jwbt|_vo(%FIdSK;kglDDFA4Xea^pgxvV0Jk9s``;OUahAhE8>YKH5%d*V;f7NbM!$m#f6M^Z^TsaGjjb}ehOIZ}wmYN?m zdjzh_@`fq!-n$5SLxu?xtfU$oA-1R^FqGyeqG?>%xsY7w2wF`Z`zu&145i$HQ9~@8 zb3{HU9FX6$KAL|codM0hR&5xP!{e-&2Carty3dx1dm4T3RVkG^cdy*#(|ZYiRWo}D zelNjqaqT7e=CzmLo0n(s_d*sg-o$6gDgu#nsjZ6@L_E6GQbge(xuvtAVA@vHaYn&Q z*WNd!5q7L>9Bfv%^Ia{U;450<`CEH@;r@ZL{!a5dA~ zl`N5ES}$LvsjgI<%ATN4tvh#$r{g1%(z=vqfM6Z8(~JQEZAC#%jerA&+z+#axWEZD zi)iS6!k7E?+NpyxxT>Rz>qrL<`Uy1*B~ZjYJAviv#QGD|{4eddjx(c;AbSc}%7Q2g zp68V|`(Q}UFz*(08mlUg>zq$ks;y%m!mB&y8|lsgN19W88BSVQO-~AjF-&HDU5r!o z^wuS_;;X~0g;#fK5MG^VF?e;k_wnjVF2rkIIt0!Rmbpkuj8;b>)8PUR;A8G&Y6I$G z`yr;;pPA;bUGS=Sp~J(gV>Z}rO~LSba_Kbj)mcI>xtF9~(tTntx&P!|;)^YGzwa+y@rTCFx2n>r zogY;h_U&**WX`o_E~wh?WC(%@liw}R0q+$?PP0!QUNunY!P<7q6{_HZ@Vr2<2jCq8 zCn;O+knc$X(VK*Q0v{QEY|p0lY--P@?t@KXO@Q_#HX`=q8ns0z>4;_I=ZcjxB5zob znFT<#Mv%qaChIA0E6F}mvjpf1r=NGID%= z(xv6`u`B(@D@cT-^uNHl=Od%NbD3PTS>GlgSd?=2Fy`{aP>JnIY{%CVuotw0#*5o> z#C@dpht?2!;k67-4_7OoZ@D@Het|-51>mrc)+|5(O&yC+AX||D8e(9PHy0$<(>jaOY8z8;5pJ#I|8M)@%*g zo>2A0Wkvx}ZLqkX7_P{fAhL8+)ebUN*(RK0KM1y3(1x81Sw?fQqB$Q<#oaI9ON7uk zpUwrarBt&CPe{(n2~;dhrd>~QSLY&L9iEPOb-E5gM0o>=diNv#VB2_H=d>_O@L%Rs zhE?!yfJIhAa!eE#lZ-{bSr=T`jA_BBw?9|>hGq;CYpL*{g>pP6boDJZvf<0#sN1_{ zvtEC0+4jyvuP%NXEmSXDfIp@Ozx5tQPJ04sY-elIdP!ep6#equdbFFZFM?#d3ZAK> z8En#a=dNEU8q!q?T?h2XezgGtan}M69VlPyipoT_$m)pkB^3V-ocMA~Ue{1-;4U>{ zl`S(Pq$XS>S!MnA@G3fe9~XH$U)XiCZbiEo_qo~u&4^zJ0QWJjNbOxxYrIvKbPN%g z#Pa29J}Mb`HKjtZEU3R|ZKYIenoKdwgc7rlGo}v|nM&{}CQ~kaMKa;*kk+Lbb^xl` zRzd0zkMY0)GTL<)A|b{&jWx7S^O+js%IMtaP>y_<_MD@&ZA5wkB4 zJ|>k2g2xg5Z7Od`D#paB@Bn%d)z%>6kxTa$1R6jV%vhF*3u|h_kcx?5Rh=`BxPP}iY(_^2HPc8HJE zdZ*vs^0Xu3LsK!)T}q!JIsvNllnHH^WvR#^ym3TMITo*i_aPK5A8}C^Myn^)9G8Y~ zIQ3pJjb(=*%UtRyQ9Q3QO$C#c%4RK>_EVkMamGI34sS2?_@-jv2a>DmT7z@aPo0~X zKJ${0ubss{vBZ{DD6(q8x2mJFM-boY?adIxYoO#xvAX83EpoRjxuko*@7>Cm?-zr8 zr>tNi1<;|__5Q=o?~L{q?5CTv!XXDmr*se?Ih9$e2>YZ$(DXBvKvkz$_6I6Nu&=2X-R>CH9uH8<9aLNrVFCPnol-Sl+hM$0T93<1XdudIzvVZFS%xJ>M=R=W%)(ni`%%9ta>Y zX0jr;w(_>s5a09SB{>zUDp?(&)ojYhTN~?(P~2R-?940C^-BF*+#CfhH7Ii3EF|BY z|wsfY#pFHm=%CH3~m!F@h%i##Xc3nNOkaYA4ee zj@)X>mv44AHsm-Rjm)wyJFZ0LIfB|ueVx6!RG#OKJJIqH%4fXQ#%`PpuBnDr?{C}e zXHlzDcSiuWSW?QBAhXBpGym~tm#4=kZ%>DL`UIIY6KNs2&}v%^pX%uj*t_p`H!_@W z&g~y}BLD`o#odC{rDY*AIav%He1~Q89|$TjpaZiWcc<*?X;*r#o;pI-)be_xo_-z# zdq6c}j*4i`0ruu_+iD=Rf|WVPER;?4i`@`^Th+pF@{28(YfN?5Qhb0EB^!98nK928 zR8{v9Qh1&?OR%#W<5StJX%P+zyE#KV)}PL@S&b%WtzmS62r{L0$Q32O;Tf9%QYaUb zpz>f?tI(FIjGa?&&0hg%HLR@jckcmo7D6goE1c$ou;&MZ0hs;{|6w$rG&>^SGy5G0 zsJJChG`XEh4^awzttkr&8pHVPQ_swkMxw@}JbIop!2PP@44$Hvw4(#GV{Y%9O^f!3 z4Q7**J_Zjh|tXrqmH}fYoB}d_u~sfE3+Q8MdjRCu$&vk73M&9 zN*UYc8oIcr9urj_F6(XYkA{;Ax&CM3gXV&3PPHsM^9@EVdV^u5w9M@;I&)7zKo-bv zb1&7_M9@Bg=4Zm_iZo%3G@Cx4Wn$ahKl2xBL`Uk4xi?Pls(c%$)~0z;5rxZfo1}>nNlb3W($l zR~qwZ@L?$9g876-7q}p@B)s@vnx^GTlq0OJ3jbCfDToRmZF8t+g~f<_|LOvsROC;8 zcn*5OS6}|&dCP_PRI>_6*EZ44BP%|WERrZ&1mI+hw0nig8Rnd{OcOVPS(X0u?ouY+ zXI=b?vMz|v#z)55$wCergt9vG3>E|y8x?4lr`3eEiCN!#xo>aW+LokU1Q>`$Xn`Q-udnVJRnS(Q72_7vduo0S^D5xA z?jm!(W2Z<^6+g10m^FlBY;Ee;a&3@DC+n^De;bM+6+8EQKPa`^$&h7NWgQN%Ehj!2 z7KUd>X--vho-*YDiavwYS}cN_Zhtx~Y!?4{<$9I%o=D*#|cJ$3PE3MpVl@O|&AZKIE!;&nIatV<~cMkbu==&|r4ZAco z6jQ0C=s1UVQKKFn8mu5&^d^xj#*}AR*Dc0(iZFL6U0o+X`v95B9*t|mX;|wzBqe$zS=qy z6!$|LY=Jlzv~CX~@F7UZ{4wGhVVf}+Ux(Hxb58k47Q^WbSFd1avv9e2Xo^e1X}ijWo^t|M^4y%+Kmg@ z?s*3xX0ZWXjux^EGYd~Ok|7%Hg&z+tDqH=q=8QCxViK;wTKaIol(T|uON@>Hb-ID4 zL+1XL7VVHg;uu}mW>klgj%1}>%%1%n%C~9hNZ+apouL$Uhx^wN=vEvv2d8!{vi1q1 z$&_5P*#J*~fbXNquVS_`5_On}L1gNbCy;Su z9=FdrDtSUg1rrq0l_d?t37c;-r3i-+=Cr(KuFx>ehUCI@(pQ^DD8U;{5HUO^tOQ{` zaxfeo;8D4tE=229(rXXtU!QhrMdg=l(4wE)CQ33Xfa)Cm)`WeM@{>KMkXTO`!( za8O(L+T*Kh{L>E6PnThz+BIZ3Nmq!BokMQs9RQoTD|Q`$d>hr0-bfd*rPMR_q?C`d zF|gFdwQfSa%$+cX0=w5b+M?{a>po!W+p8tbt4$D1^NI}_L0JiZ)P~u|FjZOtT4&81 zhUBe1igA(Ck&;=ZeI<$o=QK3xusyM8lY1;UwLxCNqpX_)9IpWCLh>_I_MQ10dVh-iD6|n28y;awa%NiJuFU~sDN`qFH=%wKk zd(Cu{DticG^>8sfz~VlC zHRzElFF^ek89U7@K1DAb5y=(H%%MjbCYwU0FA?*b3L!PD8`UQn;F0&y6k{aNAo{Be zoTeSioSiKm()j`+u!w+m7u~ERau2J?T(zjuB`klmu59~m5vgR#a*B8)jzETA-N|nJXg4{m5_JyLr*;N}eV6p->aIL$@shw(N@i29a`Mb|+}l82}`ShQZPZ5jRNx zM@_o>vqfxcgXnv~bZ>*$+aS7V@!o6@!NKjA=>mI1n26_$5_KtypiHz`^3EI~%h*?N zFdQBnI3tDKAC(>t{zRBaWQvQ*v|lO>LT#;;hkeQ2w?cmdwB7BJ=#WFXkd)W=DuUI5 zmoEcm3FxaOS_!NUk;!<@ZGA$+E|}7a9OBJkQdE8Wz%XaIEN6ZHkohrs%RX@gQd?4$ zB@;TE{d(m$N8(2;zWG(rChud>6)(#gL;$RJp4xB@*$j++ZTvBJnYbZ0wA?xaW6^al z5?jh|xRP7vuq|vdB;J)hl+i{kD_vCDo-S^0yOMo=Pd5bL7rhQUS5U24DPEHQclhzQ zzYLE4c6j*1^TD5g{O#e#A^hWuqrV;f;{N#U(b3`I58uB1=KaO#kNoJDA4HX3<6plV z{=iOu+^~_Oqrd%Uhl8ME_O3G)jMv~^#E7`d%%Sr$Z~)mc}a9xb;Y{s zOfAIJ6)>G*^9Y#;2Bvms8MZjKi;cqe$Gtsxlj|NMm25qmUwN3)l|@tD$0*HR z`xvG9YagR@$7>&>tk!#j>$QvK4ija~bHL_C#6u8I&QU z!x|-ODyu9dCHsdHK5TE^hb@FARTxVBS=%@*xGgI7nAjluRPYiu+Z9WsNV~R>%(Y+3 z3g8!FDM>4Q0MapO##63mKAr=&y%AdxJJ>D+RZj$=MNvwcOqmM4hC-+jqNp zAAZ-ewQl6wrIKxdh3dLU|ML)f)PQaFo3%N_6hpDQ_<>GmaTY&&u7n*X*p zHz^fcSBl-DD?7*do^YkNLinz0-fZ!5+rxZf^y5x4>7ga3(K(BBk}w6V$Q6YH<1RkC z1LmOEp-a1gt}%kh$`!ZRJO55bJr5=>~P=6cb8wEd{C?$hT6(Arjut0E2htE3s0V` zj%{{BSJxT}0*TBrTVPC%$tzY&{pTJB-JUY0Tp?vQa8n1SrI>BN9poCp;x9*c1M+^1 z%l!e-S+;@Vdlck-Jdl0|5vE_5KNJJ@x#-l0ZJ&)%8BJMA5aV}3XQ`$NRU;m#Zrr)kc`<5=xm(oH2aV`uMLYwNb1SYf}iHv>$8HFfsC z^=p?1nQrGm+p*d`p_<)pDF_W}mcQ-$pq@Q#wf#{bg#^1COaAXl$g=CH8%Gkh6@s!g zq1fD>J-#?2-{9lBLqRE}MwRD8=9G5>fZlAhiH8*u;le*l?88PVs>=;mB}<95r+j7* z4|C%5=K=9>UntpuY2M}U)KautP9Q}1SSO;GP#nS=f(SeiwIM9sC+nct-6wD4gbT;T zq>ZW>Q=YXW=Uz_!mC4CUWv7CUvh71A<4xe3Bd;?$Aq@U_mU3nOPp+=sfHSxfPQL^< zr#)MIYBVyL-SGuv;+-LQ1nm(nQZsa>qM&5^1Y)K5ygLki95M2K%9HDh!2c^tb58`f zA|a*u+pbO{JFJVY3~E7p?xc3?^vY5YexpjsgxB#0V2Q4e?-Y*j-BASu&Ta^Ta_$1D z#jPm&1XZDw!iA&T&WM0(yfaACy198sQ>SJ&T;wj{)h-~XGFS}l`6c9`O)Z$oPDrmkm71vEhT#7Pu``oZ!PsM}QY@=;ned}!cu0TJ!vhH_gVK}JU zTWD`_CEi>${euG)6wBAraF-pb&ZM>F0lOl%I=dHH@!nlE0tEc+#~&B4caXOWQ~$i& zqn{}P{(ZSeRa7(P7LG5@NK!H=?Lad%Bnu=w=RmR&p_A;W)+{e{ z+m*NXj{eHLqxbHmm{vIz1H&!AKN`iIG|s~zv3vo=3b2JjN^>Rn&lRi96<+Fi1kN4k zN5`~7iK@Xx5;>Q|WeMWx=om&ImPMvFJ!L4pT|kk9`l(nyLCBM>_K7P!KNd$K2RX5em3N~GbHIML zb?$Av-on;mN%iImep)A|+KM%pGVjvio?Z+qj&e(^t4Ap)?}g-*myfc@crrUX={9l$ z+jPgD@=+V+KKYs|mXfzr&y4zDi0etTqA5m{|{f;RAJ3&eqoW|1fi-*DC6RFhTT$`MUSS!E2dg_>p81Y>E<>9|muLeVvBe`Sw0KCCu9mIm0* zwNJ$*D$Oog`O4-86MTOCn!Sr(b7K!?j1CC9{Ibf-;gh8eh*yx)>>OjY3*ZT+_kA*| zj1b3EWaFMM^?5r*m$rF{(4xpVhA_+0`lSPd=KN!uu$DW@GIx_*2IPj7qfP2m+*K^0 z1qVOQ#!^f)amN>D`1T^hvHKBc(9Vr>Z&=JA)LeX}rQ?e;EbV2BE!E}^qbE=da;z&n z(urwN6Dj;hnW%Dx1)6HGF{3<+S>1YVJu$kDQGI&7P!Pt{hcf67Fq7UF(Nl(V)E(aR z__=$Oz#XFk?tGpJDK0IkK3u-pZXukT|u8;UojH$mZ} zAt7Jj?Ayt~J&pjr))ZW2S)YtKK(=dEkkGAl#YJM&K{4=%JkTSjB>IgGUQ>{nS(ZXE zO!$P^^a+?Oj28PUtCVKtr8Eah5Viw_L1_5%*Ic9!r*#R3PeKJ@9E?GxN$|g$#ZoWI zLscbHGo)T2Q`Ix9sD~y))jKkOHOGKaIKg|*Xu*3&eF6jm2cXo`r@Ic_SV2eMY876F zEx;NSwX5%T$~E)w>S$^5m2R30pO9lgSYBwbUXz?r=MrZ(teokotpws2$de~}JAyZ` z>+3}hJ8X`)2VWdC8EJhYJXuo05xo@|zcX*fB*a_DEj|Bu^Ts+>kXGMvkt&a-Xyd*u zy%!Q0diWFxJTC%oDz>g@-bww-np)X_RUO{Sbn(`S=Jzak*asWbb{E^06?bRFLY-js zbgUr#vYyli2jG*zFJMi=I_G4Z(Mi3Gfa{^4_3G+7Hv~oaVv%>POuSAC9@JD?`h@w& z!XMX*!oKn4t7#Kwqh4vqTSk9pv!lUEa0T0(VhZt7ActIi7cG-D{avzXui5NYmWyk# z$8x>rL+%x)fjQ?T+6U#rqVroX)s>yk=!j+OyZ)9Irr&kkD;ff<+Z0t13{i7ofwG)X z!T*WD!iixCvNV4lqU#0C2pLQCkzL9QS?HRzPScd5Aab#0S*|7m7uR>0K6oCZ$#Agu zJa;Sh`ugp-+6TPBaZ!~k!oya+pHptZg6~3IyK<z-mB$xn3(3;WF$;DN+d(6xkxI~f#3z-kR5lCE zxD)~chJ>7<9ZMW&LWLBw+&(IjtV&tbBKS>jBu@#gw9KjI2}vX?6Y#NyEmevUy5!xY zQd;IDr=^I-(Y>4&b4abX89`Jpbc9UVPUzT@`y3Yex zlUp*4HPv5e zvl3;NnueB7^pZZKa4gp|sW(P~_m6{K!MZ&6i^9OcsyC zuGXAEiO%;Hh05Il)ARB9$#OH{dQ;09(@Il5UD`con76;go*9>l1j(D2*h7UsIb3o6 z3@ip=+9|%b+^)2dYitvT*t#sgf$!|nhc@$%tdciqAvr52;O$D*czZTA;cjHOT{~C6GT$t<(#%a#@I11m z98EX>GTa9!^>4_dS3`2_Ab!H%tk*AW#{%}| z^{&~h*Pol(-kIpt36IfadL|0eRu6vbZGRT5WR{!TlGe_fy5@^r{|kkULv;jZ4}n-q zvIH}*xf_;NF{0`KDh~gKlHdLAtECU+^b^mk{3ZFr?|=W*@0UNu1wQs-`S|Q^dv$s824dr#U7(!}z#DVH6oBVcqGXAj2>wr&I_w+>h=D5mZiy2n zQp7MdXWo>GG+PxYvB5~g9o&j!aPr)VU~lU;8sq{bR_nII6Aj7MYNW^*uU0753;H;x z_o2!P_kONeIfDe7TCfj-@ZQ(;8{9CgM1=)(8oF>T#MEIjjc>y{48snb*Nhw!QDxb( zM}=JFUkhosMwQ%5$J^8_uz=DJY8(g$-jOK(xXlIOfH#V#-8`0dvob*&m=W;0OR(*R z#eMG6uz=T{;+i%yGA!u&qcb&ZG5Af)4hx39H$Kb}eA6hhJ4BFeIFlO~CGgstChl|+ zZNQlCW~SJ9R!hdkjl?3`caq^Q=U!}xa<{-)tt{t--%zAA3N5MBdSmzM5voQV{Jh;n+(NDUQgWIPaqp*i-c zprV!&ZwxPAwW2m$Pn({#8z;1^PGku(QKEzuGGdv86nKoV#Tamx17cXRy=zZBTX2(! zNnOWFWdQ1HIj|ILNG`1ivzb)12|L}8mEPe%{4}VmWekk4JFvacGUv&VAWtG9FSL+r^oM4`{cvL3H<-$ z^v$XH|EqWB=cljU8wutM1Pw3>q?sCX63UoQQ86RqN*hL0e=O<+Me74iQ=_atxdpJ8 z;7x-~h?asl3pPb=y@2*GD{SK=lW4rXEwf8L3i4W(#A4F{SZS&bYz~k4_YiMA%jD$1 zr}i+C$q7-_$fsO^5CBhq;U0@JRr)^fDtOB`9=#Jj5Vrda0Og`5&5dS*Up!mf11InC zvhl`8Vb=OB&(egJ>D+>cGa1(lP!FptBlvgSxUG#MZ&;bp0uutD%r!(z!ADM5!65C; zfzvaQWD?4-;DO$chmH|cu2!W>zVzFx_jxi{h$Fw#(#Od2rG{wpcq&;*Z{s0X3xUvaLzja>AGH#Igzd54*C!`G>kej_tiQb zbL|&R_k-6pls~|tyf4-Q;%%^k0-w@` zn#z@b<5fnLT3~GkE@B!c3|l7DIozP$`IO$QD2TB^r!_4nOt1C^Q89bBvV`7XK}kP>7)tjA7(35#AjWwe%V zoL4n2+w<p2Onzt23^DONwLM??+S^Ls{iRplTetdYON`Z}SC)=nX{xKa z)ey~%WtLZ%erQ#ZD|jz7Y|hu4z#2C2oD0w#68oarpSq+Rm1dgg3i8;gw!xgX;L>jv z4P&92yh=4rSgF+;s`Q5(U;)>~nVOG6KqE;+Y> z%vi<1o+D+->w`x>$zAh%O) zqYuWiT&loy*ZI}iU~3yP(&zGc zz4?SC!@c|~eL~5UD=kawP6Y6}k^;Ey;<&eNA^>0cE)ZH2jCx!vdo}?uRml=rrVBgf zOalvLsfC~KAhR{2O27AgFapAc+&C70>=5hGxY9pT)IUl>1)48gSjCyP+&22TV zTQ9iPBnOv)hxuIUx2rHd z)|7wPWJllYUT&=sqv_1|2tB~CwKqw@+Fd~>To8oB2=QmWSHdCh7E4piy zSh9X<-9xJ;7_UurwheURJ1A@GHJ&>(wpRSRV|$AYxXr6kN!q+}2}~Nj%8B8?3Dg%y z-fh`aY`?v1@<0f&j8}M9!>TIY9nII)AKAFQM^H>r;tY7LTXnl%Z<|!gTDivV zsjiJ;@-8_)Q&A_L9(ovrn2~(Bbga?qrL2U;-KTG!5C1%T z{u|;`OpRc#G|h{bkn8dryWm{$z9OSS4Si($Fp(vb=70HbRKXJSZQN&M;WO59X1i!h z)zwrQ5SiuhZydUPoe|1$k2h``>IAoz$yNcAY4EuiZmtefjYeh{JWDOj>fjyc<*5fP?3jkc zEJjxP!cUmFs!5P?iLEJD&Ji-KG=wdb!eK`DJ@kFaOuKQ?rprQEfQUEY+Og0?=6NN! zo;?F@$VZi#jb|ylVc9dqCj(k0Q?6N}tCBsV1s_0X1;*dx>3?`O-qbml9x#hUgqYS) zPLBuB_K3b6m8gXx$){KEYY!t9M*<25KDL_JhEM=qWNX5^Y*wGc3XlL9H!6v$Mmg8Y z1zBRy;VU>npsXkwYKG)Y)aw1clNy4828Mi_6FWQr=U-T$N4XFfl1{HkDy-wl3G zA7goai{s$qI3)s-!^?9K1uN9L<*M9(Ea0c{PYXg92AdrtWQ{)NKE2)y;X7cn7AEGG&(M z71+*mD)^WwJ@jQ!)DK_&I1JMY`mPSX7b@)109I}WQ&$xA__c*}pfk77Sxv7E|HjT% zMwhu}FG&wo6aVRd88Q6dJ#u&p5zjsIXAeKxP^!X7GOTY(1$bF3 zl8}+7hRa-%Ygha#i`D|MbrVGD2NDW59^xu{*-k;XTa9RC@X`FRFyiO|#s<*D&$b?# z6RGcV5*%FNhEJMro9%)DhgN9~I9yIsWPw!7?tK{>0)o>vnGLL6Za_t9{;jyu=Kj_c zTVV%{sr2FOW#X2 z$u*rY`%ySXY)u2yltC5fw3Ob`-lH|Z_H#)$-MMHhEl}6*_5JO{tsF_Xmu$TBL5~cu zEd68vC~!-EbhV!sKCs?}*zD(~!A*_V+>AJeVW}KF26yZ%0C3+eRltF=8ylGOAXT8& zi_HthyM^!^c6_bdZml4_pig^odM{2ta&h`jdtiO!!P5}1?=$s@VLkc|vqlybCb zshoQl)rLWaEu+~XIp5E3XM+CnaaU^XenVz|=3j6Y8mplXD#3rQVnxL} znGTyO%&V*KU~!VVS*ED6Y)H=ZfiivI z3C*&Z(OMb+Y3&lYHaH;WHX9aP;WsRJ-4PlMPAs+KXjdh21r*qVu3g&4-9icHzox2f z6m?BlG=h<_tVBwvhUwX|&#@2p;T-;}<)?0pje!TgPUBl4eAP^jePT%!#CU}<9NXC% zyG?!FNnYy1rj&M_Iq6rx=0V+?i3%Nro^MjuY4gHFi)Y@X3I$lq zA!C6cpiI?NZp|4tO;3F5xt<^?YzL?6dUswbIwqEHtAV%DEPY^wM!TM=%K{_i*X{jfv3Yp; zQM6>2%OmCRnwwRZeX(M8gIHaN2GymNq-GnOxL2pp`TKJTbaf};cAX>Vf2cF$Y&C}k z>2WUk%1!5%X;;3RE-1sF#Hx@&aU&8#^(=S@@m}7&dE0Hy)jq*$pJ265uv)jFHb}7Y zyBX4}T-2WVx6Kl&x4W-sz3InSi-%)I4QbW~7QVI**0@7anyzItpo+hH^VYX}4=E8T zSLQRXWWibb>gv1AV5v`mJQJD3)l4L3hQ}_+oSU1ei)C*|GY01c?vt5F zkc*pV%&6@5OAx6_3(H`e4epVGm0YIQ36V@$a@|m0qtHh6e{3jSRJI-4AQhk^q*aaA zkyA|$p;}Y#56|=75eCL#^cO8@&NM6g80vypf3Mo6TsGlsxm88gai&t0^x*)KLtqhz{P+vNjA5gkavG zwS3m37?L>N^P>Ptkk?Y$Ny2abi#&TqE*s93ky&RJ)CY9Ov6Kg~nUxLAi{A=)D;9kn zzC}y+l6>qP-%y?z{`axhCm(wkHq@Pq$w!Nn@v(Qp0J1*)*fY)k7Vr+=vU0+{WwZZ+ z#{BIo#73O`7eXVN`{uNJKP%XO<+SiO-qOOq97OT_@S_nEZe9%Q8U5)WN{W{sdqMSA znVXeS=-I~}iN5;sV-LRT?z>LD{Ma*JGPg^q<)|9J{MZ}KG*kT-{gM@Zb1M8-{e_Rc zpUj**dxr2XIGKw4dod}Bwu~`$3OgOnOk6l#-MLjroAs9!~Ba) z)BMmWFT*;gzQ!JoL%tN#WCY&NsxWkU?J}K3g5jtO8{?jVXEXBRON7&cPtURMA3ps! zT+n5%$e;U-{uqI|fjBBsYH>+~I6L$x6m_Ph(`TTOh^D2Kyo-cK> z+`%Vpea>DGpooA#bEpRqgdK%TTi-2kj9ip5trDZl%dwLQlaN6HERop_R^(=%4AEJQ zPbE^oZ{lL2>KdTHK=9PPoiaFjbckRJy;3}dlnY8G6)iNKb8u$C^7mtHoQ-YUwr$(V z6Wg}!WMkXr#!tAhZF{px-rRfN-yc&mJ$0&1Rae)XIn(p)PvsoElK}GX<><=%qxoMo zRaPgyJ3_7Y{MT8!0>V|w@&PS>5C+WOaJzW2W?{>e6LjpcMt-kKQ!};r~|KDBA z?kr)#=W~I6=7oBBkQXkB9sjn{tgjn7(PrS|FWKsX#x4EQUjPZRtypNbE|1=szys_? zS1a;OW0D8UAg{^DWrxblr0m*4rFFeCxa6PKDl(-cNW<);2F~IZ+$OM)+C6wq`U}n& z6$FTcg(?6&^Ft+OiExoJKz=s?F;XdMz7xM_DR+`du2VHw$0;;44!>~$%t~ZsIErON zr4plo@7t0(yNtO)r)S=UrDOo_zs@4;)A$oM%X*hBnmHx`48woMA^NVb;MZw{NC8-@ z0e*Y-_#eR2>}r3(zeBOat3iUFOcm`rw_}X)pBVq#9}9e-9aQaxL4Nk|Qa+*j|ntiqB-``;++Cwh6KK&eCwl@3(NxN^h zGrKvDuj4v@)b%oZI81Nhy1a~TcG@~jx6WS1b^4fIi{iRm$cjJxB9yA#BwMvsC~P0- z(I`z|e}FvaTbVqn3_ccs2mQxE2e}=$+?SBMZae3L;7!PlZs=pa@!fpt0XJz^y-mHE zZ8<9jYooURwINp)mD)7L72<%&Zk#J&3Q0^A$5VbvK!FMiLbYb3DyJ1u=%o=1u2|nF zI{OBT7?thY)Jh4Mc*Z5HTo&#?-eqIUw3Y3)ZSrebSr@44lRuqdgq9q3-aoPEcy-1}q|qfY)-{?2j|`bqCTp5l>#Qy=gA^M9rdn9vI%_InsvXl1Dg-ftl-`tNod9)6qewU>sO zHxAz}78Nz2VjlUjYeP$RhsZQVQky@8%Qz-_-_tDWu?mZ`gs47m<+PK1>kq-SsMyIY zaaQ9P_z^S1>h9kNiB&Lu7Tp@D|8juX6_xm8Er$lt4a?N%x4ypdlb9ADwJ1P&kYX_j z44@OIjm@0KVA8{A1Q_&G!7dXBS9vEQ3h z!aS}3u)}UWR@RR0&m^>NRse11Cs2b3_&u=mO52;a&p3(zouAkP1d~T4Bsr#;-G$qQ z#r`zlA!u^XK|@jOw0@I6Xw80E?Zpq>SdD@+Luou^ou;@{0>2alorceW-dz7HwabG| z&1CJx&V=otbD7cpM{crzJAZQZyWW z4ERQc4jL+fO~z8msz4NkFK#l~2e=ra3LZH-mofKa8h4 z>ttI0&DawVstia8b|z&e40$YQJmrk(#O5&7*^S21a2919z8TaBVyYiS~kyTlU>}t@V_i8pcZ92KkivQQzZ>UYcQP1yd^I~B; z$2v|!r)eZs7tt+HB^M1Td?`59l~z+<#e0xQv9L`}7=m4A zw6(G}`iac2r?PQ1)0E93r^(=uscL#B#S|gTTpGQ^lUbD<+L&7U8p1EL>N$-HbkO1e z-{==f8VT5`0sQmj-yOw-d@spMR^X!AYb-5#9L`e_A5FECsDGy#_eqyylyM(kyMit} z&Fn4X^P!*m7QKTaT${d@X?}8ECKpdNTIR0NfxNZFGqY~%at_2yE5ZM({X^B_FP@Yf zr#%t6rue6ou;(x#0%EY<*4MfErN}ULXbkTu7c&xD8FWs_@diqwI3d_Kz}L&){Szq5 zrLLju>96l1PUA__;9WtpXc473)Ey%Mka6f(126rCqcK60a@sIWl(1Zx$x*YUpoia; z#G;?>X=K9ir} z_xs@jcztj0ue-jS`QZ)(1a@h9LPq;}%4l%Rk#!dndolBJg=3X6B7g!~wuCjUNXt5p z@BcSkhqk>6X?-5lc{ieOLRzjWSo`mUd&bdEsxn)*Y0jr+syr)9q$76=IvkExh3*)j z7a*sz+1LxMP!?c69w*-sbYwQed#(7(N-1GU4VM>_VeK`(FHDvLvDQv1bG6inRHJ8h zk6;KoeT<79FBs)HZ{km#ByV_W-(0IM&dkA&s&d??-QDSA1iXmdNqR0>t)CK*&UnR@ zz19!~$!j}*shqSttnn?(Ln-dRnqTU+;x?AIU%jprgN~j90PV?_(i9m7i;E1Fm(qSL z2Y04E$xD>L6cIAALJH7ukR#=s|4;ByNfn#CH%Gk_XZc3>toZHp%OemUGr#Rzcwj~t z%F@ze*-5NE_pO7!SRBmLAhlta){rjNr!1Rsboxi(eej7a8A`RiHIK^dC+b{O88v zvwT3u+6g7z1Wpc^BXy0s@>mLy0{i1469Y*!|8nJY@8&67l&Qch=tcBWFJq~fe;n&&y z{L2C7hZ|;KFiZB`i}%Hm>_{XretP}iaHZbv=Nm_~?|*HF4vrwr7nD&$`#e*^2p7P` z^?Fx#+jU)Sw{0ALznh2MmcFjX%JSBe+?IY`bZo%%oOVJ&He~xTXfuY1xprm^H(d=X z)CIbQssJC9#?t4>B&!G2MBmei-G`TMz;>1D!e9Y(UC%9*mR-s8uII|-n%2Lw=X7*i zHCVwL73IkrXebOWY71e~EDM#)xJK+9lQn}FU-g%YUO_Wsx=uGhX_i`z$*8{Qjlp%+ zdGYL+_T2K^2JKBds`z%OgVrn=SH3@uR=oJ5?3X+@^~`=WLFHu2CB61^`r;ppijojs zcl$pH=gH)?Ta@&86hr{?8>u>4;|A6wb^)Z08hMQvC|r9%^sjiWX^a;3yOo|Boyq7Yknr`}bSLr2$f~wKIY4-^>Y5MNsybm=Q2} zQsfx!>|ja@GQX-jKBlm>_yA;;ufg_E_l(?xPD;N%BWa3*pa|!=-Nu^lQ_P#RCq~}= zhOZk#M0jI!?jhIpaN3(%7_c=ZtAs>mUTx+jmqowx;r8hZ|H>ihnHVxDR8|+)fO;F< zeu;1i0gQs+mCyB;bG!$#yXQ4%40P|((KRE{wqXb#wdB>=pi{E|rUS@P>#{M4HtMQQ z93a!hvOLxgk>be*bBHvMFi$Nj2#&lYD-z&m5!cP!b*gMEA()G!g32&xjWZ@&0^-d* zdoiqR=~SmPGkX~}Q*)N!sDwUfgke&)#0?gqV#_&-fDyQszC^L~9AGk2Ba|YFQ5F>t zHMh}slT~K!$gk*dQN7Hi&p+hK#&sG5KAVdH=Z7}~vl2Lh0MC>08%xsU06sM%zQ#*q zqQ}M_%&#+Fzo9X!8a}k>x~( z)*9fGqE1%(rCugG>GP{q0P1llW&4&pR(4uS0JxdI+U{Cp%T5l9qblvJ&TZ|oy_#>$ zZ&y?>b#21h4G`j?0Lt1k@WVrshHZ$GAz^nMwf>w#@tT(R1pW<+?%)`2IFlCqh#n)T z`nuO0NAXLxQ}`dPNAa|E^d6heW6&q@6;pMEd;t*@@m+23xyx^1RW{9goD2c`P-=Fz zyfegXm*QW)=an%_z12J0Z{cM6{r*lYaAK_Oa2T<-`fTFf(=-i(4O1#n60=KZQK)Ik ziSwEBTWT@<03gXO0^~{@gQ8h1LY};lnX8Dl%*K5g&20K6!`#Pyy9RY?6TbtP2ogJt zIQn5fT-!3!vZ;Y84TqDP8NQ3$p;RKdX2L0E604~jW`>Jg9k8G%+p#5SQH}>^uuu3s zG^&L^+6!#EU4GrA;ZGP9HdM)XTY*Oe3>|xWw5}h@@TfK+{;6h2$B;JRfYLEOfu1wM zw;MMV9rnRFY&M2<$(j(0x7?F6{ou;CnBj^y;6I*XHT;uqVf(hB^V!w~+-zO4`}f^6 z^mMl@sy6`i0cKP98PgN#yvg()dR*WB)8pa)uTSMQDGq!fcq~{9P){N?3Z$OVu#M+o zr)AyT1;ka^#Gc0cON_93ES90Br9ncB2zE4~Wx;dWoRT-VCM*dlxeMV|(4!Xi8zy#z zwj209q>3qk?u}Cj)Er02`{Sk;j7E3nZao?X5*1}!7R(b`+hg=36Op=f)$7;I4-X~t z2}@3V#xQ2Bq_(SiqQg#MLxM4Z<8>;21y;6)A7!O_JNj%6VZJ;8>_gTJVFFiPz7df$ zhd=ezr{Zn?czaL&O}Dx~w5ohq=_=aL3Ep@Z)6!=X&O>)?YD-pFR{1m0HObQ%F{H4p zx;{Zl)H7pfTU~KT;LZ0&0yd3J)bh4|cp?EMb%|__0de9|jYs8#2llXir}< z!O-(lF34!CCyI)$)+!(0h)ZhXN=y$4nR*8Vo7r5As_6ot=u_ou;-O^m@`gbS%RPOn z`(49mZPK3nsg~VOwUsTCgv_q}M)IiRwk?1dqg0 z*w~*?^zcr4&oC#gT~xbEdmWMdo_ourL8Rq*=;a&MQhI%Y{-bqt8wL-~);=Eh1g>4m zMO5SOgz0w*i~$6hzNGGxitQ#t(UTCq1C#cRL%OvmyTX_@{lZ!bW{TEtw=SMQO!hDg zxlA2o0?Gkz0S_YZ!R;fi0pbHRsxr59U`Luhx&`4VW5`)!n z+8~}=CQWkFl~^(+6Vr8(i=qCoW7k~dPpYkaOG;1}S1y@!LjmuuJY!U~Kr+uqYg+o# zpGKJ4#f((3>V3gCP9o*+XXrCgo6KNg>pVW2G(aH%% zy9bYE=9;~o0I{9Vu@vp+5scCD$l8Esjo)^TeqLLg9iM~r5sJ8`Unp8X3Rp({ZHe`| zsAlOOd%bJTQ8snJSB{79v1j~h1MxjZvi+ZH6F!`LFLk5Zk6P0_F%>2?_Q`dlJeF?T zP;VB_)?|8QG0kc3?8y!88>M?Le!1HDZN1#Pd6Z)0S&5DL&8@ZfKG_Ol_Pbw%1{A*e zrF;&z>ZHCYmM4#q(Y64~w=KRLNZ$Kd9&}*>HIPAKjsY>?4ZlHG8_>M}H`oX1u+7O6 zYg?19t+R7q*#9;j0k!pJ-(3%V<9FB6I@6|Ck-)@j9Rq%=XZmyezp?bc!0K;Hc8{>7 zwRRxCGAI0wut}XhSUD0{DaawhfuujO}RS!1!WcCduDb{qXU?*z7Ba2^N@5XX@>%uU)=6T zd)L%f)FyY=pt9#=lh_RW{AH3X_RILh(Hr|zIiHC= za9ewUkBGB5R+3Fx=$^4Zdjb0uF^i)--EWQ#lZ{ws5@O+auh@~xrOaifEOyR!+)d#D zTRN+ZdC661n-(J(l3qH!S>QTk^2G>$r`PM^nK91v=C!5TQy>20=T#Q)P@>Yip+UoK zqGPC$K}}xAG0dLN=;$vivt8@8rHRgxYF6gG9^CGLYPJiH9M+8BqCGwRm)TojPcSw6 zkBI!suy+skJze4R^R3Tx4RN>mRW}ntCjIimw42xHEd9ZOjnfD}B84A>R^`95DAE^? zCtLL9T0%XoGUGtKY{|`J3_d*lz1^K$KL7r^wBeq&p3n#sa6P@;Znuvk0v5my2L<$h zT}><{U{X5FA`1O8A!MO3!AKF|PER}nOqv%aXHnh&bK3fJYYUAfE}iWB5!jG*?0=2l z+~!he$!W(nmEE+wBVuY7=1D*hQyr^CT8aG5{0;6*^J8)QCIAV1N?T8i>OzT<>8tOA zD{2oC&X`S2jFt1z(fyB{)!#iVQzrKS!hbCnL{cSh5ci~)>R_jsuxkhf1c|H<2pAC; zfy8WpN$0upOPWWinNhX`v@#;kL;E3+8Ax&fukp04t;jhjw>hZ}8IINX^|g_MsqU2< zgJvM1TH6MDaCEF$->v7R_M%!?4K=B>mi*40%^ybH*pe`kx$WHVwPOFEo$WmwShreX z$_5Xoyj%tf7E2tlx@%K-0BXv;js@&m>(SBeIwq1=I&I$HfEvu2v}G4}xZE_5TEF66 z0>9S~ky@4_NQqj`;t}BMp%16Slw)Pzy=O{K;)yMZ{HCcF=Hg6_T_fI@`A_}sa1iSd zsH@_EF#db%QPH^7!|UfEr?9_D!hs$g7d=wc4j()BKtC0yvQ65qH^Q%S`^q?l^ped= z!I~PgoY`ut^wR>J=ZLenP)Uzg%f*tb3BGigDO`mjHX7Ywpv6tF+2^QG+-cc9P;PWg z3|*VTrB-HdrADv*FC~>E|2l?0(EqrQ_%I(M)u+bTaO7DRBrD~W-Ei3wE-LEkc0 zp(o#)wCBC#*#MoL?9zTE$ijAwKKVH!L`I#lu*z?hz2m54iMX_& z{c0i0nvM=VhqUO1+GyE&FU1_EV_OZPPm|4wD?B8VhQahi{RL_XoWh=z4J{hebOT)K$e+BV+1@|FH&1-&La>H{;e{0rv zC;rykWkW`RUD8PwS2S%wpzU`9e%^=r!YblpE5F^9k>0tC;)YI2Q*PXA1mgRhSSk%% zLe`uF%6P3Qn`zObw@6??Mf`yy@EOVLHOKVval+sK?m@+eq;o)yp4dOkK6DMBj~1iqkM3uM4NGpA>TR zl1TG=tf*iD%W(|}(=Ku>!RB@}%6-c9=*l4outx)SIGC_pcW_SyhTW7JdCgf)jqW=A z_xZr@>#px>*{`eqn4EgqVDG{lJTM{cvS$3M;yOgp4 z!*M4C3c6KUtFq*=>sx;1Ad8P?H&q`-qYt~*r_sHLWzSEEvw7}@6IpEBbFK=$UJ~je z_IF#`LoJj|5rXU#Fj54m(v1QO9}NrIl)GQXmOK=`)TX$c6|}s+0h+61)V*%Z0oz;> z<*Ag&=L2E;jVN(NOF`n-HWPfb9KtRz@6^D*61e&T>a>~`ea4r{GRM{l`$WBjJV?;n9eV6kqVmTR~;|C^`7z{35YpuEyHNEPZ^l6B5pgjze)2 zu<>r#@tg1T`3dsDMWMS z)%ISe*c13_*+3k&&(Z0YFVp8(xPx=ZL|n2E=PDfS1;u=MYRVT)w+BaCs{fXM#ccmNh4{ z&fQtUd}iA%k(nw0~J1OtJKj!e>f=O>*hR6IGI}9kj$zA}V=V3Ne(ZXsF=X zIj&)ZVZy4;OO1?;@|Z5xe47T^`Y1L%=QvwjWkmmHV9wv}C#Lw=qfL^D`_v`QGyf%h z3dw7=cTx@JShd?mK`ZS_af*aGUU3y*IJkh}8 z=f9(5%I-2t{|nUZ$*jTKl66#X0 zh`l4ZtxhHSm{69bqt?)K2Yy7cYS}BjV#MeN(hX@1RGZy+I*^WFMx;!|#-G_xeN?fi z_@s@ z`$DvB5Nvl%by|RWZ4%ClF&B4X4#hM;tD`^=ShN0GDzvD=+J4Ag1BcYD`CKuo&u^|7yffb3ZT$3EXQ~GcPipaH!Fa)a-cX7;q^orkisuGbjpGkLh6n<5FdsP+mf-?oO zv$%p3TpTYEHy=NRwJ(Nx_Rjf^Ie|rf~!l-WIXrIs|};TW@RDu9eIi+Qke}aMU^N7cI+# zFknlPWzi|;Wpo^J)i*C>z$DO8`J}dk@G0I-9E@88)ZilQ)cWy_pL#Pg)^g7Ist^jvplM}}Mxmdr6(Z!0p zD3~l(q1FyNVFP|?D`dHI*=|u`1M|s-wq%B}$Y(YS?%WB(=pb*Nu zso zBby`wlkzxL*KFsXJIrWf2&fXRC-Ts%t;oa@O`)0TJ$OwZH?w|ckym*V?GO^8_zO3y zgxmq(H;!>Yt#1>*OV7=5v|v0?+_&ix=U=n${2g%t&B3k^O<`8YdmVjk%vBso+J>zH)t#S24Q zrTolRXn6a6h^Gk}nTU>#2u(}Ma)((c>wn!*Jr}lXj6W|PFm@#sF?%C5m*HaS?GuHu z20a+qb9ywfT0z=KPg0UqUZfQ4{<620m6J$2wz)D zwLvkI1T6yq6Ai+b>Rbf z6U(uZy$Yt%7PUkMpn`QZIB?=r8S?keVml%=fucYVCq6FF>azpQzuI~;lgrp#H-j5B(q|}ozPLJe_u~t5!{?m|-)I`M{CDS@WDASr zjax+|j%dq2XHymeEZK{x*6F4&xd>Hg9K3t_qa&?l^H*ic>FszgdtBGO`a$-jTH~$S zr{c#$&V`mDCVUIVn6wd+UDeJjsBg#!xX5S6g}lVUgqFsvn++e>4P=h^f;zW0X*?yz zGv7+4P1-W)(fibm7JF(bvqiALdTauVoFAU~L@Wz`j;9le7d>KOon2jBA)F`XF%5l% zK`cltP!vxHL(2tx?o5O}-S3|f#L~=lk_!KzZ8UlPx^Fs9`s(%fP!^$64}e4;L8`|g z@qB!n$^dtsbQz~SP6XWxA!5bEf?>Zp$NrZdvP!g%Qui}KK%pgU zr;uZ7N(N=FlR)~Fo|N>-jUlE+&Sg4_r3oMgX_h8rdZa^LR=@^RTuNNg1ihD+9k}q& z5a+jvgncC7i0pfwRzz&@5(}OwlhK`gbYIY+rq@A7MN3Reo3d7-in6MwuhF*`#&IAx zUcf^b7UiCp9-qcbo7sh6$Z#Q)xn(wWiEeUjr&~0UOsLy2Ro0MZXGB#e4+1wisP4!> zt1J+GHl%b% z6@q*Gm9&*Epu;6As0IDP_VnDqhI^;mK6m!`Lj4?3AV9-IU`Q^5=B%lN_$Q=qTtCaz zk+w^Vi=-LJ{6n*7yxp@XG8NBf{qLS(5`QN!x=(%nBH#2%8-9`p4-Dc{W@ zNlxMgF|&_IaT-IEZtm0aeIpa6VltIbD5(M^=^}b>WNG`m1Sp+m%IP%CzGy8D#YYtF z()3%`R%K2{%h>p>YHTYAdJd@)U}iMA<+-Z4N@@O>LtD^-20>*rr-<9vo+37JCwD4m zG#FQXp9D!{1NHHJB#KIyI5}`;+zUVk7TCJ!G#t!IZMcsbP1CeAb};3D6>utc!TT74 zBSo=@@Jp198o?i;#SIXE7>qRQE@Wfu<|&g*NA^yG#n9D15Ky$!ULP1bsOV_X;8Uz- zn@sxlhg7gBr`w2}C83uIq1q7O4~yb!NI9wDndHnqj7^gtkrYu?l$SiwQB4uDYQyYD z7M*_cr8r#2LqXKZGI9qfATu#YppVf$#8PIVuI8&OxOFn!>=^>NosWG^o|Bjr#ljq} zkm-L?R3x1>A>06eY6Exp=6OzrMLfoQs(TRu>r^C;(eLh$$_?VOhmSOGbhG{wE`eLS zKz?x(Y;*z+42oLUU#-H5Wcst}9#ZwUq_pjtbT=dTz=M=2^!XQccY{83IGJmXpID`$ z+NY>Ik1MA2_9~05Y$b)I{9V;W{p?N-@|$V4_-HTO*&U*Io0Cp%w{U#cxEt?@8Vifb z1HahR6AtQO9X-V+TMh9F^ z*Kzl2YRve40{m=e3c3mAa|w~{CE;=8-U~Z{YcCPgQE4Hlen0@XyC;1B-u0O`y~v)CA$_1QG2GQ+AfV?&jf+Bx6qUlTW4GjtPt&r&A&v(Z}lhOHpMu|;o$IbZxFsK)g&LtCQ#z&mC@Q)MabwBbE5(~rk_pw_e_`oe_2 zUeECZac`K@E~IyJ_E{ljSC5%V3m%R!cUwPSVWlTi?bS(3t2Ee(o@VRca5}qD?yvOk zEY<&tO_eKyfN}|51IGhn3NN@Xyo|OXFAvA}_&JmG6ZqG5zC1jr9 zPD-36B21bX(A7ZnTdm*LIxbv;AWV})aeI{eO@q=doGxp?J2yx72ueAxZPo4xg?PdH z2DF`4`Cx6-Wj4*>nhb+IUxh$Rka+z7+$L#6xlRKPzD$&eYFq$4KJ&xEvWe4vYb|0D zK{uU4g+|yjo5vn)KFwHV>ZyzarzupA7k4nf=!K&rCLVt{qWwgnOMOEnnuVTCCG2v6 z$>FJZ&{*Q1W?b<%E8T{oMpjVLgp7=Orq$3(CcV{9GoR<{IN0Ps>UN%hYEdN?t4pE49(LH7?)_GOAU@rikpnn9%6%7V?ol2&fim00Oo&o6W!pu z3KHU@c`HqXHvG1PFl7!ur#SMs7pWk?Cg^DR$>ljD6%mEztK2)2l?5^`Fk>#0`YS72 z3IT@%Xf^T_dzvfJu2e~7`Ru}viog0==lHj3e%L#C%7iZ{P|KG_roy?{!FPv-KYB!~ zVl@Q%*m)8?WBK%Az4sBs$x3SUzW+U%+4;B);?p^<2my!d-X=Eiar}5_pCr|F=Di`& zAv>Sb|8am()1|-+@zW<_cS4K~{N!ljs1q&?byFAP6VYF)1S`S{>}ZDVr@ByD26e)Z zY$E#BJTEuD`1*%Cv6mYxEc3*pRLfDn)LF&%<0uY-5YB zp?iEjt0&xo;&$}^D~`9Z<{q^YB0PtEN9;mfFB$Uqx}*FL5Ut=n08U8q>mQP?^k2f( zZeyt|=$)?!+5@}7>MvtkXW_kb&_AX53!!5jxO*Gi@8!*mLu_6f3S#VNLKXV<;om5< z_9biiua`lVz)o}iqSDZVNXbtzF$SRGzfWy~Lapl7@z2$x(tCsmZjmc7RYFf&*-x371bWNFsTRG%=gv?n)E>;!)yB zZbBptiKuRK?h`&{vm$Ul*qM&Me-$m7Mi^tbnu$Le?nqRQmsHQPg`#!< zXt-w(-$8U{*0H{=6vHH3967i3N!+m$*-kL52{rM=K&s zrGH5Z=u%?pMZCtWj!Kim;DYak+#{l1&h0=)A;#Dt5;}uJDRn)y@xXPTY95q3wH~7P z(_M&;DUku2?N0`#)fit1zNx|R;|1jD=SlPA2E1^i*79std?NYzmW>CRstjhx?uQ`= z^~l|QJj3bbS>4tAT6;5pK@`@@f7VQ$6~4)hZ>dSVkoXkg50F20`&CJgbf6UV8(*(irJ# zT~zv)@BRvFA$Y!bcRE&?FEP#*!j|*K?jem~_a>N*PoL2~bQy0Ad*Ff*PLkdt1dizx zw=u@1v%=^FF(Ur*21941bvlKeJ@A)s;TL6Z*L=&Kg*s)sW$#tIO3cQbVS?Y*ZmwlD z-s=$<^;|!}Ws9d26LHJFNQo;K(Y~JDf%j5TS7dIgZdgc%4{7UV1B=eFuC#nK*GZQ^ zf=|>aav~ONV@g?j9Ml}r{CFdJ7lGqreZ2%7<)LrLA0*A+2<_5wl)%S5AmNCCGQ)1+ zQWrxpHMl{tJxjG*cVAmNR70J!NG+3AIp1(EB6BpcEQZH&B_|!vCiu0^J9_eyWJn9V z&XO20KpYEHT(S^nM$!uV$4?BwETL3D?ORlJCYVYGWD?U)E2-iQ-s~|Y7p~%LQhzU` zPLuJ&k!^$1$-SbPfZ_N{=-&K;Dd>Dc+T;1wsdy9}t1J~DsnYBlRYPnUL2aXkG742w zJ@8Av_d%AI;Bg6|xzi9-`6caruox2KUoP{IDyfk&l@!apm*$LK4?rdM=Nta&X-N6p zs1ciz_+#GVxt=v_Ym{tn_PFs5vm{VX)-m4O;%2jvjQPvZJ^RnEN=Yqjt)$Fq9j}`Y zt_*F9E7>#QUddheiE=qe^crOgT-H6=23;j&BC01vwe-eDmp#`)6rZ=pRYPG+cGe?~ zSRA8;YfvwTAA)bJ7o?=R6D?M7%_diYmjz^NWLE5{Bz_}qt>tMqy_2OXnAd3x1=}*2 z^!2r&ooP$~8>nTtNOPG!h?C7bG_|@Me9pwJZZUx{BA7PoKVi1;^AI2wIdWF8)$8

!!2GX08X-OJ_be#VgokWV6C`q`f)I_)-Rp1WU4+*(1OOJ_ z0{@ls-%uiK%5Acb^FHu&VSz&RLxA76eE{g?LBPr_G~f%_$8v|5OwYtlS=eU!Ez{ec z$oFokU&LpQk#920=q@=T@e=JYBcnqP;vj-Vc0gYm7W7v|P#s9b$C)`2f%Su0u&+RT zWLn?tWCzw$h=IwgV>PLkUO5}ckBml*#XM%+b?$Ou#-9iczpum!(aJ)<_vR-_F*LUU zVi&5Yhoky&ZZG`Ni@Gtr;s(i4iNS7{0Kz&pNq;U~*mf%m(~y-?tI=AZK;HWw!QS1`5{Xn6 zzt9}tcC7FYlae|pF^-Z5Zu^2V$S~oJ@!08bJ4j~FlX|HKFnmnbbKYdcS1_?QctA!N z(aQBeRGSBCKTZd&=#SaIwAgesc6~}DRBmf)JFTksrG&c3g%Q)XtmM3nT&n19#s=xt zN%s!qh5r!Cy?nAbgD6OZxuwh4!y+3kDu8srBMhzIJ+^)@VE=Y+hNMX9(2K>~AwnX{ zdoX$0J3Bw@GzZ-?1eF6k????}yx5pBrZUML2`b2~v*rR$ozGST>K^N8mI66;Knal$ zF7#c84pUup!MJrGKjoq+j&A{=snSvqB1~fnz3 zMpRr1&+NpAB^4>%qfNd&)^&z3uC* zE&jcr{u$@XLb+O5$@z*q-+oLDn0F5_D=_OnwX-=yL>|g2ntaqG-sO8_opI2&mHo4C z)H#@}rUp@iE-R1eZ&t_Fqe$}_=)#ds+|Ki2Wqc`>Io{&QtOZUOpbOFq&X@QmW6bhv z@g~%7A3RQs{Ak?t^t7pt4c!D-rQ;#1y9%G1BMoF4%;gIZ6l9t=k(fxm++o;M=IoGW zwx}Np1PGj{EWPmwWSB)xrQg<#K%u{Dzf~|%4ocXMGW5_2)Kks*h7SJ9==g+wT%MpD z%yjM&E~nB*rogH}C7pOB6=TiHxUdH>ZZ^VgSAo$Gz%c8Njg`T{#vPAt1A%FB*`UQG7jTq*Zq5Dc_r2ho5 zbNOVvvDG3WuAznjjcP1Kd}(tu6|kE|j{ zRSw+447YPiwz29;`t6vOj8r%9q3dw`-GOGBt9AiUMqj zZS^D(IsG`5bTjH8tknE~MINlOralLHFang@LW+iYZuf-DTwF2VMneXKJsZwGc(;!d zO12L{x>#l!&9BwufC$sjnq$_;!r#>(L1mEkUn>PudY>BdNRx=R6Qco zQyO|3p#PB3#W9r)EfM>q*2n%M3AJSXg+Kikga&T7{;wbeN=HA(OSsQy;sqXoN*s{{ zZqjg|^MyUf8rJ$jlR>ct={^LDVWtrKE#=hY|4%80n$Dc*5FD;7^`26VkAn;fpX4Uy zLCnGkswdN{ zIU59P=i3`7Agv752D)qK*&vxgZnH#T%kCvhh4;b41sy=>(Rc9ugTih?KI3MDM?yb{ zm+Wu1V7=TpjD|deJPSNX+cQ$_C#m9Br_T0l96O8q2v31F4>XrN0Ia3=juN$1ALJ5a z;pR+P(v?S{Ah_I8l#$?_&e1IS%yKQ9YB{+X&(rvtF7SXSqEcm#-%_mcN=T)O#;@t9 zvrP6BjMm7zKF$Tey@5)|lq^PaU)M;79{%GLUCd(N)iGqQV@Vwy5FzxElIBpXlDRNJ zCmX+EJxpmL)gy3UiigymO|KV?AEM?%;jCqBppu$UP(_@q;A-f?3t6JPFW1zY<&Bc`rCD3ve~Mb^M2n@`gKvZ^~hRgInUP? z%Z%M|y4???yCO<_7Gy+@ldC_W6rQC}@6_X512)7W0bO@@Aj1j_2Eyy2hVjJl1F%|n z7!@*GgP0*-f6jMi_#(}*(2LI9RuiRXw_=h>0Zolw+6Z8|3Kc2@v4rTgfSR@nBKK~C zIW7;1wmsWDpM+ou=?BT+%BC~e4iu$u$YD8VJ2Fy4@(bbYdAM7U(Dr<+cv6NJ6Ejn8 zQK#)%XVVi&g|Vt^4UCjCxbyfG8>#f|OeJ2@ny6-CT|y+wRc;O;&mVAE7q(;?c=4Ee z(NEu|-9UZQBn7dKySKL=98Lw*6gY(4Xj zH02{wtU={j>Qp>}Ud_}`(9TONmEuWQQ8?1xZUx8uT|G+)oF4r!loP)Mx7Dc|L|CHD z!C89L#__|HFa*V=csr~=639trrNXj_Of!lZ`BIZ|E9$;dPk#C^g1$vP1;u5cE%=jh z3Ad?f8P)yNP7aEioQPwjgDt~U@RaDJMYI*%(?2>TjE`yh&LEIi2vAVO!@6S!nUvc& z`f^nLUpsTLsWn%~OKA0vc$L>(7u{&I?<7FXG;b0m!lw~N+cf^+9iApKkDc`t9iz+4 zeu6Bu)W)y`_xi1$Mtgto-T40aJJIz+t5h8qNfkYzw@^>Jh;v(u*sGBg{FrRo75JBw zB@JXw680l;>GKK@mS3Ekn=#rni0@VGB zzbY&fVmtqlv4qJKiJbN#y%kghc1Vh?J5mv(LJ0b#V$#OrsSQGrB4)i9=f~GEINzh^ z9~vu7Egq+&1-7c06MS#Ht3Y}9no(HEBWHpXF+xQB7gAuXcuF!0Ho9c{vKnZK(imCH z4?;9a0mgQ^`1?w7C7^<2M!iIKlhw*4ci&Y#Vd)IU z+tUU`S+mD``e1X>uB8QBwyx!QZL&{6SEfM$Mcr$w^Qijmle4IDJ-H?9pVq=-O>|gQ z(oRo8YikVgf+!0fhn&>WMM(n~6`Z{VBdnnk;G>O6Vs8ksSt_L!T z%dZ6QNCexqtH}ja=TS?y1VpZz3Td8v7|YRntYCa8r5!;^ZUEuu`BtSeBr*r`TQgKF zrR9~}i|(3&ZIg|+l_4DsdWmt(!JmMUsLJwm#V5m{A(7+2fo!;hMZw;t#G3KZu-st9 zHiE|uB3aYC7J9?5XGqPmS0iaUDS8XRnJenX30YhlK}4b$oj8`-bfUvawFxR3(ucEs zZN@=_f>u?r3U)1-4r9Z_2V0Rxba5>t(p0M0e>@`t%}r zxT248ywO#bvDgMZ8orLLt%G|3ho#iZfJx!skO65?_>PrjZ#y^K25G(Qz*4}JViTB} z6a;^f>6%qFVAzL2Etl`qFrtImQvL$RFA7r3r){^)@rN@;1y2#r?`8JIIkL!5;aUIv z$8Dbj_ooz|dicWi)-)`-3Z;0#B&w)sO^lHLHihiADV7vUbB1mq7EHO@ zuhHZQ;ZmmDHyse1VC58rbCi=r2el`ptmH-3-}*K%^QCHT1y0O(bfN?FujSwiaM~Mw z*5cPzqF=9hHQ~5kkz-X;~B?N|ddilpjckH5tS?FY^8u4ZCR!8z}xGz_6$p z+jCO%OIOyx@JDx(_R^dc0cuyGi0Cf!G08*Tz&}>&Qn_>SdE>Oi6-ae~@+0!@gQ#w$ zJlecmtUKX`icEy5%bg<3)e9+ZsCq3GU&-D8NyknqWMtV>R>=gV zTM-1w$~s+yn~ou=Xi_c5*`ih>5Ss$NCgufq7Nhp`gv5Ynks)Bu5L0;XUi@2k&X`Qw zm&Ep@Tp42iMw}EJA^|Uvz&QACCK9M_qU-G%^QSL9x)WweN~kQyt+d`Ir>*GhwM&nE7~i}H6Y2LNo&oq)-7Q_7ek6i&Z5AL^9X>G%hOqF3g~cm za!dam9M4NAkZy2m{5QD^`~|F{Rvv!GC>fI$r2m!yW_p#o-O1?BzR|p*WnT(yiPIDF zm`v%3?qKNuS^|25p~1p(VWD=h$=_ZBOfAFzpY>b0S=T)5f2|EDy1Iz}EQhXDl`!>+3bFqKN5W+Lx0Pj;uJ;0^td;eACT{ z0whc`KcFyow&_!AKbjLo8`}mQ*T)s+M=g8oJO34(Feb-xCg*a(1dG9i!)8OeEcns5 zTlh&c+w9)}^sqSyUyURSMC13oaP&$2CsqOkNV3`?zT9>)EKiI;zX%2RxvF=83k&-T z_}@x^Q^t#3H5#`Y2(eY6TJsPuN?wK~#-o`eJ54ENgsMt4%#kBpb^n)whc!04Km1lL zW{7{1u>F|hSqJ#$Fu_S4LJI3lf;9nUe4rc2(gCUDX+E+4AsRN}-A;00;#mA%ka&}d z*B<73u9a`~Wsu*Tp^?BaH=C=i`R@o1DH8j49ApJ2e+-=juE$rc0<@l@Z$iM>jlUJr zb{FpfROikg*>rQQ6+W3{L(&LEk!o4F0zVA{E^1~D#8|YGR!76ABhePN(<{^#dU7yy zps|SjU=i(WNqB6v=vKP#J%0?Yl7E%gow?Y`TtopT+I*ht1(wto z8;Djg7Jt8Cm40ccbr=|d)zTa{q~|r$Mk*&yO$=$&hMGAjOPYj_a>+l6Y$?Imh>XE< zn;H3$&pS*rd#F59rWx4B9@)$k3VXa8b>i=cwU)Dz zk3apf5>VG2O*hO^i}PHH(vaw)ZjsiL7<*4Q-okb*uX^`t#HbrqZ}VVMH~vej-k}nz z3L>>mgKq0zEWkI@n1y~vOlGt%j5Illb}b&$O3?dHw;rizTfW8p2&H~nG`lR0rC}Ka z@0uVAci8Wey|vSSykjHl*p2`0j}}tI(hsyNxRIl{ajUd* z&))W{WI>}gb}2MG%(Cfx1E0#g(AGN*gv752N5eO|?OzOW zX{A=0p+K~hK25I~r>0rB5ZxF6s`B?#t%kFyrTC9|PO=;n5oUR-3T$~*AeDRW;pEKq zmmu6Kd8#F}CxxcordrTzONR6^16u~%2?+63snsK$u5{L)EF=tKAl7~V!g+@d2~*m3 z5qTLApCYwXT%5}7ErR{v30ff3-#d_76CNA)t_iu|NRyy>Jr!@3r0^m8G^bsY0794D zh$PwB9D|;EiCO=O9z+>MczZc50{VUktIMb#3hAijk8HC$Ilxx#iG_P>n>{}wojgrn zZwakm6MYIREX&JaWSTmINwsqMXCJQ!I-aXuM>~l?)KBg{)qV=Z?02F|oYt`0{y^%5 zck%cmBubYRBDG^Rrs68eW6iByW>ha$h=`7`?nWq|MH~{7K(R zY>L1#>nisK5j1GZU{z#c(S;3eV^(Ds!(g%Fq7L~%ro99iyVq2M4Q^&Nv^L*ynGg4mPI}>*tf*3iu9ACCl zH2+!~cvS#yoSSiM%^mL_LqXrFYqkKC3dbjt&xUAwKdFC~Im!ezBfnlbaD|_Okh%D| z-i;Dcqsrg_+fMy2 z2q}*BwD#cfgy73_DXNAAHx;M`IqR+>eFx{~LFA-vs0kHNb zz_!xCoN2pt|N1iMuhjf5-Bk8=xUi9JCJhveCP_-YwnwEcvx z{v61X>?}JQbvxS3yO)meQ1nsfL}Y2fh&^m6YVnF$8(XAJtRXre(f<j1C=C*=$Fo#b`*siH?i zg%s{p9n^6TUhkQTXG!)QWXq1E{VjaU?(#)n7xVog;!PnJBlA_>;9$vgVqHM_l=7Oh z{MmBx`tn@VltNC^!`nzt?`ou;wtl}=a5wHw|9ODiOQXL2Cd?Xt!bZraeFgJ-G2iNz z&_mDm7yh8>C=iaG_{`Z@!iz=kx10ud$zj!w3rottb@Iw8KBD$*8UzShibu+(2|5Ur z-(PTQydf<5oXF8J1b%)#Z+CFZjpZf}H$vcP`)!ZC%?J{dyE0KN{4JrpJb^&@Fu=#L zJp$;$5Q7VZWpChnN>NCg0Uwy^7Bgo|dP3k<>i%kx!LTv5ObKthEko~~^B4kRP%co* z>ff`5EtA}Z>vERMM!-!~!6gmYM!lVa%zD<8*;93*f{4DB1kBYj$FB<9s@8s%(K7HPeGp2J^+Zse$e3X&&w9DOc>~V@GBSNv$`kn`IcKYPb-r%4m(x{S zZA*)5SDWiu+Bs?XZ=QEMPj@{DUv`@em@+LN0B`5JMoXZFr>A#k!Z+G-8Vl54XI*b0 ze&x|@yZ(LjT|w>G_U-^Xdl7QTiPkaNuv#cOqNXo%L zX2OMZg%kwjFX9KBLE%u2wc-N|mvVJ&IPXtQzVIDCHRH|~ej&ZbhNA30{FWaK+^0)L zlheRx(Dyb|9s2W`MMUfv+0v>X3#aj$h7LBWps{m|1HhAs9U zK%Dlga?tvZU<~d*)NbAY~YZ^wQ1|ffn9nXTG-3`#s z4jp)1ARgoT*7NTE%^fN4+;nq78B=yo|`HaWyF5V(>& zKpM~U$eyITbBXiS(M!xz0X;}9G%$vc@SD^*IKBEB>EcCPyktc>W7dn0WTIM@WY_-H zxNah{1zNwG@~!exGEc^%**PRirnjSG((1;u_GLPzbaEoPnLV1lZQ=o|=*(rz8c3zb zT{Mp9=~e@QF%@4uCF1hY(XKB5!kLj6VaFHn*W{`ANNB;=|9D9$#xO&SU*50%XfcGb zz49nU1fg8kekLYvw$o-!O1#MP;>Z}ib7Ov$Fi=d?sxY=N6*X3|tJ2JET1n67 zsv00^ULZ<+x&przc|5v~U2pX&q(_chkydZk5X<;JrTDZm^skg1vBg znFu-$2j_$D7ok9Wtj>Qybc1=QpExQWUcyBgYO?3n-K*}}1r7cTevOw+E&5aEf7FDi z!b?+b2gp(m!i^;{8Y)RCl88TUCHDXaP8AROR5#QYJ7RADXRRWjcnrby39yS-5I93y zxAH8{G4G^08-Fvv0F_C?D*IYQM5BON1xAw4L*&Iqtb&wIwXd8hLKc?bFKW_GE-Chl zdcqTKEpRaNj~+dv7)%PjYE}H)ib#ARVtN`0=m#T_`rAqWbnx_AF17$0Y)qTg+mT~_ z`TlUb?2e4CcI>2ie0<*qIE~B^lP>tYU|;#bmf>hfYF(jD?Qi-8(uWRr31+?6u+KDO z<0*A;hX-b2k1O_UD5dY4j%43IdxfGc9_}x~$4&ark3z`T~H*^M6#i+t(F(pG%cK{h1Aul+F^wc z)o?WMpnXlwRLui9QP~dV2|usL6qA5}H}eu;S4xQ}5Z4UEh0O=8x7fY{VwJr`2waE3 zodnJvjI$e_yM#$Bv~pnDWeK|w@KvamG{P&wfK=rvre|L-VHgqk6a-nA zUbaB`Avyhip1@Z=g2w6!-?F6|s%j?LQ_}&hHKGC!~6kh&J76Z^v0T0KwLQ|mE zo%4U95ro>2cr(K51>Fq$&FtYur@VtQB&GOsN@yS8f~01&9Sv>WM=irEaoCC$Cc#ue z>(NjM_(@P}1WQ%s{NYG{Vo8iM-D*h$cGo)yy0;k&nf$`Sh8ra)PZHH6UGo+=5o*kI z1%_%}3^4eQWhS9kwf^ka(}rsEZ(Ws|;@z*H<^QYAJuP;U#7pF#@J;Zh3x(GZ>s|In z@yOS|1VQ-&n0_m3Mw^oDX~KvHO_p8`#flk8wx*%-D5I118ZN;b~k7hz+!(lE!e$Vk0<{2Jl#TY&bh0gC`_ z>TuM(=?~kLc7-NM7FRs^t;S5^q_$3XAM9AP906CHSyH7F7h$^8&{ZLGNu+WSg%=A^ zUIp=x!ri|Nv8Y;nY5as8hdYa_D#}z=0cYhl5CAUI`ZT7xOCC_ammFw_J3S0JIg?n? zwscPzV5dIRBYO6|ZfzxSfls^AS8wO<#byurL ztQWmeJ@sq(TIFS_vVBL_W#;wjI95+(Vwau!*kUZHy&KL7eT%qIhfHybOZ3jzJH^>H z?^KiKzFts~JjSKa%=jtS%Ol%~UY$+i5odfD3HK$9_mzV6nS!MM%U`_I^ZV!bNPS~8*ya=sOU_dT2i>eJ2{Z!Icw9$$T2qdW$?V2t+INo@1km%wMX zoWr*EXYp!@v7NuxjZ5jBfAf0uil~^7o`OZeX~IYw`bQPkHaD42*c~+lMn?_RM(Jz+ z{8?dp)+-L9+*nZ$lsnxI$Oe~xvJ;WCA{o&IVa+IN3?z=}Ccj}I$aed!^p56MqFa#o z9Yb}I{#bGUsWk-epy!fsWNUZ{gz3CxhnK7p9hR;lgMOybEn9aPYq`d2Ca5VKE+%V9 zei|+H?$p)1bv^8nA-xyXO!~nw3Mh%m&Ro6%WL-S;Jm0B&0{VnhER4aF?!o1W%ksP* ze_t}b`c-*xx?22=EvjSlVCB3h;?HUaONgZZ?v^DFQAe1MZQt4HcfG1B(Qj9pHXH=- zp)i}b?=M3(vuGDlVZc9+36_dMc$OYp^C^H}8}o$ETL}JSn1 z&N=65k2Fq#s>~)hF8Ye+S2h!-0?aoHe2sdxvu%Vyuk3f$6^cyGrcxX7ZZ2)ptzFLP zHV`KGALD!~V)oXCVKR5SB~$|d4Q2_zm4cBG^snoO6GQ;;90U7&BhCE2pfn~?ZLYR> z@25m8H%ojPDJi(IaAJSLsAl3M3I=L<4b0|WVkY(2Msru2Y^xj%ny+V8Nt1}DS;(EA zv2W%W8Mq20|8SjKu>2NemoT|8zxT z9R7BBOx3W@&n@jG&RQ7Jy(16DRV}(1$on}(qHg?lfIN|(EIkEaFSpClP69euwKM^< z`7LXK*;g0eyM%QI=szl7n}+ouB6GBMvtagmEkN2XA(LHJ*EVV1L|3<&w2b; zO;xcl796E+wL6BN{Zn6>jAmVpz__!jLqo##@sD&ZB=edzK>TCgk|&;8%~H{qlov$u z`5%MHyTqClTAHChGHdZ>{z=QdzrSfXs|?Q;uYE)K^~rJ5apF9ij3flx0%m!tT^$i= zX2p5hGi$vR>=*0M27n8m)w)D#@MT@IHr-2JK~<@&*OXC{co!!7v4f55bu_KcvuS1d zix%RtC?89JrOA%L)e;*-OO%UKi`K%lDn#Gz_lPzq~|j@2oFyHnbO& zjD^nsIdNEGa5Fz<3fM8&cL-KiS5fEJQ)bdV&sRj<;*8yBzII>r{EnFnvM34RJ7$mK z+|aPS8r5m|3Ai@LZKq??I5NS!aYO42!gtWRXrYTT`i!Zc+?;X3{Lo)YY@GXYdT7J} zo}P}$0o@qnr@jiFZmK5*_}%7r9u|h&wz}3z;<`>O?i|Gaeftffib}$WfpAs4bhH;f&)z}G{Ct84o)BXQVTzptE3-tVer|GOZW`Q#}SN* zhOTeR#+BFScA=eb&Ca>|0zN=j!6v-JS$9G^LHglxFb0q~ib80k0*We<3;R~y`<%kP zyi%j&oOnudcuCr=?QQ$`v2wOfcMT*Is5?J20*6ErDyGekpOnOr_GLWMQOTS_Nghu1rj<>W41+G3 z0KX)WX4izgkfdMpeG$pd?9UlPnSwB8td!Dx%HH2efK5gYFGv{SA~UB@5YHh>p=Pojk|$SJe7_;bTxsveVkU|Nw3RbRque}LrR zBZ#(z_?^$mhw72;B&URcQbPLF5BH0FL6vH!oGR%d6FMG~){tr97sMn%BuFZbrFbPy z510UW-T1vf^q(U<2!ZcTdcm|+&PJLS1VFbs>pnWPc^NW=qOiA5ub55;z8KzrU>Wd?4oN$((>XaUOc$9Q{ zv5Cb?p##RuxmFgAdgo>@>gEn`K;Q`j!pj*i#n(6L#yxCNgHeNhp(eYz2GiN)`6D0TH9Xbw9QXKo~XPJvnH1rB~0{aO$`tj7f7~zsv&O zp4=9c1A(^%6dfZ5@KtjIi<8R{FIR$vCmkseT<011P$De`= zee8?)OQB*>3i@oSrEG0OdOH-$88LTAz~a6X=>D+Vd<*;~xt2MUjo_XDoLMMYdJz~I z`M$M$@=9G=u=cLE!=^+xj^8`>5q%b-8zff#4$`1g+<_+et&|y8`16`vvTn#9Oh@7j z-EM8UZKw5OuPSwh9~HLVOwd)m(M-qDY@gfQsY#*$ywOr&(~uQVSJ-01iZANP^`Pcd zfK{qU57o&CaY^+FT=lxYYPPAed-$4?_oF%1tZSh4h<0ks&U|bS^ExXDOR(bMv$NZw zheaU{V-vkWDzsrc{k(AdWA_7$Qz8*^NODL3C1Q}*+WKOzB?yC)Nrxp6(X3`CDEa-@ z$v;=J=O35=gSQ#G5|f))kB^-%U#72-r|G_Mp!T@(5O7S>y4jxi#)s}_+|c3z!uvU& zN1LH&(}%WdL^ogdC253`YBpy4d7CwVhTO^wCvnX}O3hb&3ZUS~C zL)&_KZ&nJcab8TpXCyzLNzPz-5oLfsZvzn^cq5bspr-SH42V)s`W+iIz??%~a7R>g zeWk!^MV7EPH&!T66N*8vl$K?&1ITf1r3et%S}3GV58uQV{lDG0Z+H1rdpy%Mg2+-$ zHe6_Vv`ZFcRV>wgw#pY1$AQCSV$02a^bh`x&K#CibyJUvXFFDrzu5wcs_-hMwwn$5 zWxKPnInu1gbx)F9`v4LNw)LT!98?*um^EzG(8$QH zSuiX-3YaGTX>GFs_744vhiNNeRTMhrakGiR1ISn9j&1Fv9XtuniF%t4z$xcd9gtMm z?p^Tv!lcTp*MEq%4x2s!`@DrPa9cGu8cjFP20MxzD%P~7Mr7rz7f_`a66N|3sw}0X z^U^GP7=qOo=+`Is6=zFg8ADbaW=r@*P#JaiX%+YSqrdj{&GG6s;R4E7d!~B?UW^&uHC-c=I=MgKmYpf z6faU-J=!!il+C#Dn~C1N(YbqT11@9FAF`f{U^52`#Oc@ASskhQf|yVLSQ>KOf%M`;dK z5x+elQdoVJ{&sxumR%`E;0)AnD4YSe3h{32{o2{sp&tgUuWf1GexHW3R{&eu^WK*# z^0hnsyPZ$X0dVOV^6=}PJBRb#j-!zZm~;F}&hW!EC1)Ex*U-LahNd?%N!<-HweH50 zwC$bFK+&@(9u{06m$%xCzSmp%uU;(0IJ=O%B8hr%r(h=nUKk-KB6d{z7HlTGLrFxR zI!--4m)^!RenkRh*E#29Ye3^?qDig(eVYJq1-ro>CGuBxZ94bSx5NDV3^BMNs(tN9 zdn}KNrx(jG>rqi~M!CB`H~b)h9(1-B6_;`DWaFI`!5HC{1V=W)2=0B1gO-KdC&H2R zB`&nEpOTPSsC>uwSI#oiC<&L_9Z*lNPhECPHM3-ONago+_5u||n=riA;oe9LV& z!!VGvq^>)}Ly8gav2K(yr#sC(5b0h-l=1J5w`=aN6ffoLmpYI+Je2-Wqe zZ~?K<*P`N^gWC~uIeH!p+@~U6QwatKT`#~+wmVo^kZfqjyC)6zEY3YZtY3aGAp6HT2oj(9r+=(Q6R% zRT1wPwYwWU4zTXeR}q@couM$7Lf!i$Z8MdGcnORPG%Ki+tZ}!(SOBX#Kzb0frF)=c z!xCUut~>p>gA1Ha-7!z*lHj=;|BVVUc`c~NLuNCd=A77>c!sNXT`#_@X|{Ol39r!a zg$q$Yh2KD>QV4SS$2!_RJPR635mrAs@;hFBh&c@5=g)>eb0ZJw7BS&JBNW^5%sv^h za<%_tf~^>+Ggqd9_H`|~A0oIrPyL$exTQtLpV8JP!8j;(V>0#EBr$x8buLR>fVVUDr>r^W#@{ zZG(z(`Oc?o{vFkh;N>~zYg8OW!Hs0xAJn;Q>K`N%%B*@Ci|XXm!hxTPyq7(Tluk`+ zDgesZ7U)4lNCaH~;vijv6(JdW^nN}aURAMNz>~*<4%p7-Y8H^%0PyZ5REAq@{G3VNUK&u9HbM=0> z+N!yX6)#|aYNrz~j#>q|eDBu}U#*nQ2B21J!|M1%ob(b7>-n_KKbj|=%X_Qf)ta^^ z)<2*aIumUi=So+OOJi}ycT}gZeMFZYma4jBO=?)}?{w>r_`kZ}*S$|ZgQL~Ycvm+zYL4xe0@L38L(9tlNl`9KMhr+EGo zlwizA`Do=Fc><(ul&9iGY)F03Yud^yj5wXOP5n{BCr)hh_kMYDcXd zVa~h5l!`ew{;xBuYN=3a1vxTVXLa_o+%zXV8Hdy=n{=_DAM!kz{=bZPFBz;y(Y4{v zbn>57#wf__dfBZluPvnj>%? zljC%ud0vX`6emWTB&^btYMieu^KddTT3$h8aY(h&0zrq|`&df=z8Bo0ab`Mk^)LYb z`f}=zm-Qv(%jNlex=KquZ=mR5D*JfxCqY)|Fs30~B0=?lIaYEFs-(}FuLO0QDJDi4dy2rnciCJ;+Q8tK9ym~oPE>=PLm&Ip1L)NkYx zGW)m4jG_r%fC*qBX#VN|_hun1cjQH){3%j!aJ58`oG^&mDO8b-qRm}u2GO|$sq^J? zzHPfZdux01WK8}&V$3(${4}eATJWDSqRC3dD%L7NCNrDN0)5!34f(p)B@qf$6hvjg zVQ`iZ)@XE-4}YG}qNMQ7d%&|iIT2KCgvJ5}6Qc{=l6YEPkdo}CBxMSKVH{N;h*I4R;Vv5eSvnw}Gy!=@I4GCgEU!$~K za0%~cDq~;1ickMdb-uLk`__aP0}to#gvEY?Qhkqv2esAk_*{58!xcvvB4SpPlKb)o zcmcCUa8^LndAlc>3fm>Iysi1ahQVrkH#gs?q3spIV9TU_z!_d6{7dBIcq+kfsoY6r z(O_?1)S%39FG@X+M>bLN75wc+W-Ftf#At3kdAe+tq*^o5RV|n*j>pE3{$+2zHXd>N z*h)#;p}NvRslC?6?-8j|E*puRVS(5)DcO3*uWsfIq;2sM5@&(~wepbacXpQC7J+Zb z@{%*h0W`_ZAlvuL0=XnL?D!KDdMs&?yS~cIHVR(Q$(Fg39A*?vhDMQVl{!IHOR_4v z;hyuh^1cMvFy9(Lc5~!fwwyWow$h2_(CS<{e(e!qH@L<{Wc%adR?}I(r8WAArs{%B z(va!YmW!!}$NvGnKtjJKIZ&{@Yfw02v-ycDpdr8JvSfPA1K(yVH4HIVnj~D~P`CH# z>>aFW&^FB^3R;-GsiT_VS%ybz->7)e)Dl1Iz-*7SUK2ApUvbGU(ujv&wdLBEyl^%B zDlJ{4wr1Ua59{;}v!jP+=IW>&{|DJ4jhgWIyJV4ORPU3yt1+dc>Sg#`NFL*Fz8F(F z`f96iUfqwq{2JDO$90#m$Y;sNoY(GoCqpa7sZy{^Xk1~qC0TSLFkk7I*E%p963s8; z$a44KAAEfz7WLb&aXW)tpL1TxbZiy6e3tZ>36* zs9uAVXmU0`oz<^i?WURK7f}ae1E~ zomV?29VZOUXL0W+(Q|IRgVc3OhCB@UO~G>ShEBmwreKhFOb2629S{mmLe8%=_$wOs z8n9LLYE+tX<=$uvUMoa(y0;*-CQcwZ^~&lh2zZZ3{6SGc}hZd&B98FwN^D52KsFRIL~hry^I62zs? zV})<$GUjOG4%zM#cT~-6SKvT4VC3v%bx1iMsu>OhrxKR1ko^|o#`a(k}qu-l{H6|;j*YO zb3?=C4HGKTBpakzq83SqoHJ!kvqr{g8jJ4Mmd^*GWA_f;Y`OWjKs6DDZTGeIr?H!{ zRh6XeBxx&Ek=U9)(^VUyV&1KdHV8A3vZQ{GsRTXasgIIhcnR~gu$8sST-M6srfKJ! zW=5+Z>5)mPn@36;PZDh)0YjclXnOBmhdV}{2xbwMn=TK?F8MNl&Wc^B+^6O8{}8gV zcP?KNGC)81LQ?)e0%AJXt&t(~6FQ0OXG14YXbsj{NiyK{HSNn09SEqWU6nNg4}(vD zGT;z&$k2ZPWe=9^hT}!A3y@UYRdg@z1W@SATt9$9dTpT5YzWY~TzA}1E1r818Q=_E zfUU^NmCN_-W}T&k_L{1<$W;kYFmP(@z#Am~nN86?&n7MS35vL4fa;~SV(N=glFNZW zDFc=&)2l0B;l78c74!=2DCA(G_zavhl6IW%>%eEeCLXFHo+z+(w1mf(WwA)1b|Zze znp`P;bH}3A1qiNsax~WMKsE^vKZZ17diplVIz-biPxp`}BZXoNhifIN`^fznL{77| zCb$hS9c`5g&Kw{^EV{o@UVmEfDD%8u zc}D)oL<)$%n1SX^)Z-_ccEiEZTvW;=-^`;ShB#QWhyhZZkfIIOoR-hnmPe5YM&on_ z8>CbG%%;rKl{c@`%)s;spq&NNFnkIdoGcswSK#r{^dC`sw2Q z(THaC%2}Ln)-I?r@zhD@QqPJhc@zq2ubFR`ggU+WyV20{QmLS$A-`$M4ceY?e-4^>tXu_Z2gwO0x_XBvn;| z1+q}$C9fuH%vM|Gnx-Mzz-Gv%fK@TL?D92SVZ(S9yysr2BcIvXj7()8f*}IafujUi( z&`gM;U2I!bEM@N#@&JxbJ>^7~a_?&)yFCglH6!r9knk(vB;$ zU6r3jL!J!eVv}q}%01;Yi<&dwLDoUr@gZi>`8XJ+8*;+s2fI8P5$aC@A;9e)P2xpK zJ72G0uL&YtqdYIgxvkck-$U?0Nd8w7eOP7eU5m3We0TkFOU}0WC#5G-Z`^AIKJ7ve za!$UY)k%;;gUkxuT(}d|ww@GlwXKfq?7C%CYyGT9GBwB-CN#)nAE>6L21n!~X_tJQ zy0KKg8`jK;oG=?J#SP3*KFZXZTlfgm`S2)vpu?*aMxuB=6tLE-`)mPhKlV1st7@?J z7fQV3jbekA-(#mNINvUU?aYN-iz!@Q(%KYZVXjQ&o3W(PP@<1D-=n)FT;zp&e-fp6 z&v)v(z5O6vj!=Zek_YHB;2WF%eii)3`{RF}9Ur}Ye_V(C`G3vD|J*q^IM^-Ve;({_ zukb&Y@~okj+!fDN3hhCqenVkbWKl50OV6kOP0}%ffNB&UD6kqw$XMp4oQHrZmj#;i zpRyZrCKsNpX`Crv%TdB_K;RFSj=9&gy!C*jH;6{LW3*=uD+L`$i3p-msBn!CGxM$E zfn3Hn^-hN1j4AI_@*V0MFpZWhJKoLCA*0kwh9MoZESWdSjWTqb5}z00RMRn=;9#f_0TUWgdG$5}>FEFw znnqG07@YukBfE`R60m5%N^`HKT}8f7@R05y49!XchI5$G$ft=P{E1Y!&&KpR;9268 zFsVA^ociH((?A;L0+%>sxAM}O=Mj#w_)1^x3Jil zCTTFpLMnF$6D@fW1nAx%B0(yMITEk|>^2TTJ!issAf5mYwy8;uI+|vt0Y(egyH75l z&EoWd0cI~hzj}n-0?KYaSs@?cjR&yb#579BEDZ*tJqepIxCL}Q?+f`CzPe&lLB5c8z+9^zZX9#md?BY+2zU#KR41MAC`cvmOso=ffM)WAI6v}o5sZ)-khT|!v|Z#w6de4la>^8oXss@srAt+?b6 ziA9zx%hNW-No^%0z@`c!c_dfq6n>=Om$C0lk z1RDG|KeYj9&|WgSgmB@aH2k35yds*IY-Yu~e1y+gDrBRci>icq$<|Rpz7Y494zyG( z&`FgSWiV~X7h?adI_{QXCCE!CcxFQmMt=LTd_2q`LAx8yK)e~#XjDMb$gM^6GS^5m zN-C}5PiZ0=87OGwn>~=XtSywnm)mbUs@V5bMwKD%%3yL?sE_(XqW- z$QM%hS-E1NG+`3uW!do=zYzDAnnbrGJ4wnF3q^y--Sd@BbL0!Dd#{v*xahT3NHlh9 zR8|f%S`ZyUdNGe3<4o@#YwHUghiZ$oJ(v zAx)_5S)gjvybSoIDsFYc(j*uN!X`m#0M;1Gx@`dDoIVZs}$g+g7|F%!P z+(JPfeak#qwET+k!J6CW`I5=cr0T$Ij4t*QM&oF8vl%pzat zh{|}XYQ6)mCAJrJfLD_orOaFe?n1ivHUO?b4m%AdN>WT!gL+w! z34Qfe*JS0of_`Q_?TREh$!<)AxZ#QazW~jYPFOeQN!oL0uL;Bbh1h==*bU{eUl=p3 zT2eB?-fV_qqd8= zb_levsdd~MLn?C~ zpa|C^WB`Ju>2o6J6@zBEvu$FdKnnp~R<~O>7AJB-uNWRX`izq!0dn6hpM@+%F{k1* zm1+5;u$NVl9?|?y$Vb5dQ=`Wj#~ZR<4RSGcy!ljS*QPSN9r9xkF)~VM5Rn`j)bq~y z#K^!PdM~WR9d$uMWKbAaMUo^R21#}+;5{`7f>?dp2iDxyP>v03qz^}X5RE+Na1T*%xaCN)}Yh=$}BYPe4(KWyGydMlr+ss|mT}{rW;yp@+ zdjcg;KrcGvhb(oZ(_>4mli=BpQ?9h6NoHM(gX|6Ru8*h21l zG>*;Bz0U4GI=dcHeijV^Cc2(BD|8i?1vq4VF_9#rt#-I=4T0uDSj$dlx3lf}x#prv zjw}^2B5KDWpB6X@ONF3R2cS<@tb{k_vXyhd8m>$k?Krp%nEk?{%v&Rtwjs16^S6R1 zO}L){eQ4LD_kw}!hpyeJI32SI6I&=`*cxO>z_+LnEEQW5<_GjDNViVUE<--zmp}0& z_>)H|4Ljm`i>kzHTjSwPXpozR>bd(PqtPFK(1cEcFytN~SrX>0 z9R=w)>qA=$3C-LK9*v@8Mn;`N=kWWP|7UQ+{}5Nf>Di2og@l;9h9Y@_XYw4D9jhp+ z1b~ebwY6C4G+}H@j^Z5hIH%M~{15Ls-)ejNo!zf-L@Y}GLq51#w2pc4zxVdHi}Zi* za7F)@@+^nC2O}oZE)iq8d+@S5q^}MK{q60;gO~es?;rGV_i*nYbdS9{*rxy3@n810 z_XgX;!R{g5+1WYp869lz@AmiD@bIv|zq7yVjabAWz;KtecDHx;+uJYOyZaYAyWO3g z?!k6vXZzK`&a3TL|8MJwa$Qg7X}W(V7Xj@Z#2gFc8yPZp86wi z=sW|FX60M4!oB?Oyp|_pD$;Pc3T7`oulQyeU0c9tWbtmjvu3RNy|oxmP+FuB19A!1 zumb-VWX^yo(DByD|I$L_b{iB|Zp6<#c#B$$EVn1nVMUeXNsf%%M@n)9Q)-X{wAiRq z5h4Z3R!4WjMp(YC5uucIH}VVAiHmf11aOEV@Y#SS9mqVpV}zIxFU7z-t=8Q`#2oC+ z4-vC?zv3`+6i1?2538cz%Wu}YN#i(FX1}Pj!>CP0)Ti(6T_P(BS-MHC#ALHzKntLmxJn!BK4fHZ_q}mY zA6cY~kag3hwGFd}&1oAn#%W#$L0(LJu{ENx_YjH^%$crfC|kSktF~;A6ZKkE8yirJ?!O+Le2K`FJ`BQ? zfgDE<^(k==gNI1|Gy3)4V5{jL#q8z&50u&pzP`abhFVc7M8clvgmXUaR+CZ7QZsG_5r zM6NUn6L8AYlW0?M0A2E%3IO>#I4l<@T`s(nD%4d-`)|2Owdbfhn9aFi2!RPRfS|rf z7AaHtBEdgr^QD4IgK)JlT4B+8YmViPBoTei!ws~_07DkoXno0J4H7V1*E(E7SkNpU z_h)K_?E=e6cY_DQD2I7MdQlMez~`j5w=H^-ww~Jb0?1*nnw<4Y#6;Tw6iKwMa6#H( z8zrfF=E9m$B%2^fY+G9OHslQ*}6lw4WD`wALZ ztuVFltYm#Ql)HEoT+1oRVx{{Bv9WxkLLdTWcnUHTJU?a87r}(_EbWqiY>T_Kuulh9 zd^p5e4pIdhHLK}X^*>{agDB&$-2JVV6o z*adjZ;7nO|rFxKDuEh*l1*0|?Gd~LvpBR+aG=NwX5GbGuKfP^{+Sc)HAX1@`;n;A< z25FbHPPs0(wLqTZTQCYy;ZHI-`zZYvcmx$@y2-j+ZRD z4iX;86RSty@;_$eHwCjl3_|vZeK7)q>cngKy)9dTT@l=xiBQ2sq9>g!98*q=v~~ii|M(=zK5tl zs%%M`-sJE*_%dNeH7N;f7)*lHK=Vx41g_V6+uQHeof|BJO@cw3b;-{5_N0(u=KwOe z*GqZ&AopOXp*}T_KAs318+5ar7FQ|Wcu%IoRI(bXE_NFS3G-F^ zAw`$$<@w*!Tg${;vn&ad9MWi%kF5B|+`FpYs;gaEFTYcPUz{7}1k$=&mY*o)U$i>Lv z$cJymye!JRAZ^snQcXt{zi9_!73&F|s)Wp33f>cQ|HyeEIeRu_Ny7ZMaPd$B8bqTL zgs8#SIA%s3h=XmFcEOT~3+t8gn1_5c1@U<<73>6jOM4zT=|P_2TA$}nNs3}WG>$uN z1t{Sz?@lZ04GTtNpk~{T#VmI2&-y)mSw!iSuQ-$|j@pHeNtm58eO5ZVLmv+@_i=mt z%vdakbApENGzHK@U*UBXNF%bB6E1hxrex>v2ql@wW$Kch=aZO6ATXknSjbEJf3je3 z6;269h8v`@1}Cw+QROMUCC_Ej-gn!lesG z${Iom=w&Yiqlr9&tD9s}(C` zTuI3)8O;*Q*SMpG_X91JJn<+7Sd;zilsG^6y2$z|?~H{xKf5!M@pE{xc8yxdPJy~1 z?z48nLslSdY6RLa0wrcIA9oz~N2q!E6|;2UFSSBkD^03|Rr(Vmf?4+U)ieZxrxp+C z0NnclFEn?Z>6w+?tGwjmDS)T7Mdpolmb~%iHzRNo#VGd)lhhpC=`>S*6Cm+L{AN?J zVJx#q5=!XKM+bWgB|Ns%B(}BWN2xaw>|*eRa>vJ&(ryw&?waD(r2{~tQpa;1Gt}U9 zb!yyoSC^Kjd};Z*vOUZC=WB}hBw=&e0c(mX_#p)^spl@=Pd~pBlCMS}4J|k)P`(~A zTcB2`w?p2`+rDu}oX{wvVR<=&r=ca7R<)El7p(8CX7r&ta7xy`-%NS;0x-VC;6=XS z>rLTn7;{?Q=zy%77)2`GrlZbFW|)&QIdZNP}0A(=hnuia-MztMHtRN5Bl zSeK48V99IeFy1uW+-uq6Rv~atz7OLF7vcjZ|N-bTc<)&_*_Pi7)}D5H-h|YE>6PfZ%|` zlvmBR8F{-{^U^)1+pd3;q4?eX?d_ey=^R9W!^F<7g7_Df1jA{miE3iUWf56AjairU z8BGeOzSRP!0lRyzcB+@f)hp4aaSSU!`5hT>%XpWA5jq?>&-Yk+N8*@cfFGN=-mM z6U0v`@bsoLNiW`=gS}fY3C+?)MLB~G6^JJO_;=fq+E=Gk z17szKH=cb)BUgW{B|pw7Y@LY!%@cDW0tKXp5}|4FRsf&ie1Q8$F8zCMFUjY*ufB!8 zZz>zAs|72So*yni_$42(nV%gHP#RQ{nrFsX7nV5Eb_ftDkF9h6l&2sv0&L)+x?gF? zeBW44$&vtSP?uYSN=0 zk$LU|F=G%mYu+z#f|fI{#;tPPzSEUeF*tw6ae-&ez3u03=iTbC|^Ec#ijy|4{bCz5`E^kBQ04u5DX)2rW*sKhV0|9k@B{K4Ae}8W&RAh~q z?d(hpNog`-X&00(>(@J--QCX4MzhAhTvp@j6duOYn$8-dum(^u85DM|%90Jo zMRvx+Fo;H2mq$oq|Hl4J=XDe4T49P+!#K3OjeA{g~)N^C!#=6VxsEc>R0K01rGz@>09aHR@NY zXql?e5FHK9R$M1p1=12)rFcY@)vd9BJ{h8$irRFl;sAqnZxTd)huE?j-O{#0Q80QY zw1YsK}0-4ss_8j{JHsC?*tQT4?oo2BTD z&8juYd!G4I7hFk<&we<1V<=xvijzJaAc2*C>CkuW_8q9KQ$q!9RYWv5hK3qr5g)6d z3bSfe^?c+$(Zfj)oz9RzkC41D9k|FH=TiJapxGgaElhMAgDZjPkPD zH1gY4s*MfL0XQj6xEuWN@fuNbWGOaeM(o7LYnAQPLw@_+1r-De4HOe2e^>$JZSWT5 zEDGx*$)Ylti=A3^T?5AjVvJA`AZ*gUV7Y%Ek8F!^K+dE@&R&ww1t1QCA-zuE`{Yp1>b>+ z)XK-;dgs-)w?-g*I!0dG)PaC*Xr!29y$mQhV?KDmC?`-W%sRpc!i`)&IW&&tDOw9C z=$II%$y5#riISk5$U54l5O`0F6Y5m`CIB!=Bj5a%G*farr)MX|k{z!e`BJsh&I^WM zYP2yxO@4OE23@jsO_MFZU%(D;kR2opR?`(;Ku30%n7-q8XP@dU8ur$VnANoC+9`R> z;-_`1m`_eVD!(0~@eAb4Buof9^G_enFHVo%A9u;K&!$VAApXlv^zp;lMVGwXJN!rf zR)^NJlF5dVlnD)zs@SVH2unhImeL@ExPlfiiQ*br$+;L^iImB_VylF)$d~i30-##l zIbzlQPZmze?)E0x-QL}nMI>xE*SSXld$%K=vZAX`d*(;nX>O8;-L$LF=2haIo!#vk zZV~1EA8}OP<46G%%*TWcgIi>v3UE3$Xs-jw1_?#4V<_k?mLM78 ze+TLKjYbzYjKgy|&d*UsqXAjrbi}13a!_@B{cp)BYi+_t=c$&_q!36CL0y5un#Sl* z!g;BR_yR6S5LqEqHB^BtTT=U3eK5cYxdVq>1ka&og$}`$XikS@=1j0t?lW1_k+7;& z{G2CPIDBtZHxF~_$K6; zFZq-R7^)6ABA7pqO=g6EfeO8wa)*N<6o&>oi2VcHY~>+UU|?;|=o<)2+w_*oZ>RER z%5QC~b{iG7!sGEyk!qVY$VAPpyTh6UT~7sZF3P0}L7bb_tIE<_p;wkcsrvJUQ5-8f zs_p~C({0x7Jj`$1faNK=t5_{x;b|WKMN1yV*6D|fn>MUtcKnx}-MzzN{J*`O z-BtXTr97WM0~n9w13JH;bRB}0eu@m9k_M+IfBogj^hwU=KXIfk9N&K=r3?EKkU~y=Jb&L?2EYg)a&N+I;=%FYn(piQtTUtsc+&RfpWo zb*xunBJ0s`mad3FndktJsH{#E-|;R0ZOBgG1XwWaIm1F1_eiepcT|@Y{q9n*K;BF2}^4%hxjk+;JaakhLM_ zv1EYsT^8K2H}kl)7>!;jo#D{tS?VBQAj{tCcyHYJ8x9T#`i{!NK#f6R%-A56GojIq zaXf650p3cr&Zs{%+U8taV3Y-$1y~NQJj)BfIv%#JRAAjW>)w&0Fl9+Z)8LxP0n#!& z6}Pt@0f~kwAE6i;qs>>X0mYv8Y8Q~TJoHU_NRtswnOq2^O{7J|%{Nh>r(;4Ra{Ti- z`4LNYAbQs|hl$@dP&WxGT+hZ9B1sl90bqJJDx7-sJS~X%b&Ludg*G=e7$$t;={BH# zi=0T7(`QL#n5C4%s=`Tm|LOcf0X*b2K?r@f2IAJ>c^^UEfU)02mN3+>*{bB{TB##% z2&J*^IKzPPGX~>;DLMjoa0G`URCGPh#%C&{Gu;iFX$CUWJj@`47{snbhfe69Jfb%O zW3=)~oTaRtPUE7@O(Bv;;j0SkQL@Qt6SauuQA=k)XOd94%#Y4aPfq{U#i0K>8^H7U zEKV2%2QzzM=Hq$)X6ot+p@{JI$V0zacFF;ZQMOryFt7;iCh2D>d2#yT;)OA;D4+sq zSV<~Kka|cXA6$0@@4HIS`5a%gP znUaJml*qczA9<42e*Bb#GcuxSMQsA(KHyGiG1-eA@MU+K(FPNWJE5Xh1%i3UsrB;B zch{+vdr&X1x{1|;n`F_E_#{~34yJj%_^xO?bXFajm->3!K@^N8<_=sHRk;%(X*^!K z^v517J3PpY5vzc2D-W8yD?S4YQ_+1*TCJ*)4EgBCAY|%hsZx{IMBgs|OZ=bc|3v>K zFW~B11xqVWM4ATuAe5)Ygb6`MOc&iEozj)Pv=IzQ^dq#x6yBsI5S#NcS^)(&X#w&^ z{|+Lb-#p5A++fkO+Olq+JtcQ!ZTu?_5|he60N7tmpVEO}_1<^`*&jC^q0cl9KApX5 z+-2F`i%{gja_hg~VfYwrmQ|@JuuayD8B4H?V!#4C&PW!knbkU7K1#M!8drdYO~K|g zZUz!StXbEwK?;rd+QQc-@Z3fIe>rAh%o5Q_<3^$2XUqS$54U&s3iAK`?VatF{C^qG z=g(U&yf@m&OkYWdnPhVQlhIHi^v5x1{5u}rPXj?H8Sr?DMg~-*ERXt!Tdy4k{e&jd z=K^g7aLtfD%fr^HaFO6NMod8jq_13&;aBI;O&EAJ8pdtJOD^io^?YSl$7TBvTpzTM4@KLIrIstb-N} zXilaECK!@psC~i{Cv?App-(%Kr%jU#DkC%{FZaNTR+z~Fyj07u5sf_p7Al} z6$f5vJY*t52+1pWU7y%Ag@u9{eU=dvV*bt&`JOc+gLdma3@89K;Ht^6WxU2vrL3fk6qj4z<$QP&F z-E{+zJ8VeaLobL4_)zBG@`dH5$f9Bz)x}bGw_bQhzE64+h~$e_r*5xQsIy6lG809a zjTQ!IF`CEE+pt)+wNF)L-PiR)qVsgf7ih|_bQ0zTz}$3S=U>)I&GJyQAUQg-OD35} z-?L-{`}QUYQf8WjC4V6)cPf08Q8XS$&BiZxR=Ueb+PRyjk%wXlRuT`7K#P?RE||Jlw2o(9_OaoIbp}+h$p~N+4!m4}*w?1-Cj`1@I!) z#w#?!;o>UGcwI>&-BPNC%_UfOt;fvv>?&+#Qqk+`T8cTo_LX$?Eb+OI{O8i$@wL*R zIrg6i+k3kO`OnM4{gwP@DUZXifya==D_K^38mPed5Qc0-2UBe)^>abfYWbGT;Qrk8 zW7X#HMYipL-6F@#u%;b&jFpb|0)e!KKy~X%Oq8m4q2^<5$*f@yTu`zCCt9Pk|LZSL zhhhBuxk2J$zh=~+W&Ri#aYpI6a-eb9pAs+-R)ILr-pwpuC0?lM%J4wek^3osw&W{S zaWfm0SJ8}S_6-(*(u~fUEVFJ7?mkpXUFD}cBnDf?h6fr_^w|e9PafI3l1H;HUGBPt zO8yB@J@P@-)@Ljt z35!EI0I%GxN7|&kTV+L;!ysfG&uhbT=O$a0Lo#cH`Mq@}KR2oK4n=6xg`8%=I|FsF zy5i7^ns>dYRhPUXAs3a;nXvuA)OtbzX3B}mPEOIY zB3}tgVUjYDlHJa&S&tft2GsHQZoOmgBr_vPBdwCnRSTAR`8`HdS8i`5LSoG6^)`?T z-kqg%%)IBa*yoy+Q3jWKtqgMj86ZDJoYW?9;pQTv79deeA>c>_8oUhyZ{1bOhHRE@ zy*#c;Vp%G)dCZ_a_Qq%xABWSw@PjO>9l!Rh99fd|zeBSXflvf{Thg zw_}tySX^EexcS|}yv{@cu0{Z^K>uwT(y{^SZyE8|LHoV$>QIKZGMk3W015|&y$OrC z2vVNN+ZjpeNa1unhtJPzSdb3zD>;ypax$o)Gl;>OFfzyzc|3*yvoJ(xJNKQUke+7)0LxXhS0>E1vt1^bAbS?m07d3xUa&N89yp2L(8Om+=Y@*O zX`OUcSUx1rVHE?PDvN;W0Liq*Y^p3(jwO%UfKOxdwss{p3TbUsK?LX22=LPY^I6t= z^-2J%e*e>}2#bp=@ZXGxGzdd;c8ThiBJzYb}wI_u|Frhl}GEFS;7VFJaUtw9l^@QHH>1TNgxl zTb0vJ2dUiU-RC+GI*;3c?};655uT9NAA(0+G62a5$)X8O#28}SCWb}&7gs_%xx=P0 zlN0nCCiorn@8@VEO8QcXorcL(X}USUw^PFL7maE%U9x19TB>1JtmAw~HjH%qJp1 z@H~COp$of;XkG>~(^*0Q7#BK3^5;6aE#3lXfKO=ui|p_u5B-&(ET6&{0yelZZ!Ws!5;D-a%K)X#8I8;_qc6%OYks%%I(U(>QjUvIr43YlcF$Ua9V4 zdEW_`n-oL`R&rx!*IsJ@TsPKCqoUn# zHywv+6%0{qA0uO|Qcbq*wErzx<<_NE@+zyq3NygD`@d-ax3|5!^K!NSm+>eC{*kcl z__ZGKMgddjamrA$h%3c$sg(Cv0L2J2bl3GBp@N7B2L!S_+?vu^I`R)w^Oy>JcHGp;To`VZ4B9%! zWzn5ZcNUxxD|EHo{95z3uf2I6;JH8jA9Imj>hO4#J|Oex|I6*-{qOMLaE1T9l;`tj z<2En(Ju9x7yueHBmJt+b8dSUheI#{Qs8ne7+MrjJ*OX(0jfnOpM*MDy*0VJB1wX z)99MHX+LNOUAba2M2dne5(UON5&YT%RX0RAL7v&d8cFN@g)L9;xj+2}A^J=tz&Z4P z_vL;O|L@@N<%<3<u=OOSMKDZFc!RKJ2PL8s4 zJP#$w^&!c%NvFAXTl;4|GwpmQ8{U159dLY~o>~4cb%KoC70U4Db~gLHX6Pq0ZaInC zHMu+J6s^t0iDBvICI#ixqUk%6G!%Er)G1i>yM+{n`Zb|(Ea_k2{hcamJ2fd&&L%HP zKMGy7t>lSyrBN%x`P_XyH)~!;^RKxF4=G&cR3l6%NZEk-IqiB_^+K7EsIWTbrL12P zi!Y1@rMD}JcP4+)*9$JEd8@1HhxKPAtLwUXur zZyToN=4Y@7-_zK!I%{GZ^=P(f%>_(g$z|H??7_}-5-Lyz6V6;kfOnKDWEh0ZilpZ_ zyP&5XIcFx=`W#1-!uAg$kUQWk-?RxufV1@+i(8 zo1`^n)c;#LeLS;dq7G8=!otf+EaYHl*HE4HufM!@yZtR~xnd-VyY4kzK>f}!EBp5q zE716P$n(F>8ED@9Z~Jh&B>&l8$$yseeAV-RiB3Yz*?>oK6l&an+*t^McUQX$-Sx6r zRQ8(#@a`T&tLIyO?oIy@U{EDx+3C@KK?(pNJ`WWbl+74~)4E7&e4+XT!1~K%C}z z`76-7l>rqtt5t3vX&C^UR*hGOg$=y{4YJt zb)6-PeVVfKG@&UQO|dTb9kj?`SI=r#wY|Wc_JJ~N!lJqc3a4q}zKt>%ei#={-e}%g z%e)a+)X{~!t62FjbKN(M<4%qrB-u1$|Ij7&()S3_^k22h+N)5KwLpyWeK2N&E0ImM zT&z)NzhRhP@~m^A%J2L@1^YKQ@<^OzGLlG zdahY@&oiM6g8_>KQx{{TD9RZ3M4|HuWpf1~=~VmB#=X=*RazS}H18s&Z`7Fz!wP2` z#N0o!=td!F#ZGuNvxd-F^9{&*F)UtXHH$2GLNpz7`dd4r3T+VK%|7N(j4iUR+}~p7 zB^atXapi@L;JATytQb3MBku&Hw2F6!sHW$YRxh)=<3}P_wU~V7?cJ(%9ERqey0xAf zosz}X9UM07J|U8(xyJn%BqEik>Q9*E?xPqd0f(p)Ar<1(6*>}9`l=4s`^;N0PFl=; zr_RFnyUn9}k34<2yQn*>mB(@r1?ihS1Yy20ocCQMJ8@XU*A`0AhFBYohaiuFXrtgF zKUtzA*4CYk@}VJ15u{cV4)}S-dD#fc0H2%qhn{c+^~{8Ad9Zu!u0I4PR~v*fBy8t@!9F|#qs&&`N`?emp@%xe7yYl z;q0R2H#SJC=*Zr(aZH=E_RYIb=NHFkr$_IP>zmrdfx2OR zzZ{?a@ZtO}bzQTh&jowOM@YAi#1EW@j7GQ|a;(`V%{cw=_PDmsKPG(AEqovtv0TaW zijRFuZC&paOEuXgpVTES$q7Jc5Fp`=8+`KdD>XNzX(r&nlT9dXDTi@$ulu)YLXV^C zD%08q8?k09Hmg$(OKA(kSk>I68j*o(9%d8vUY;?cnjW~f6UE~fMtCCg)}q<*nFw9IMBqk=e@a%J7!XGzb5!3clcL(^1qzauk8H2*#h zOnDrYwuoucM;$cqk&eOUXZO+NyOTG^r{~9)KOg_P0D;BJ?$2ymLuBV;u(_A^5<71{ zS8TdSSwFL>RoslOzdb#_{OQB_g**!{&yLSOy!&)<^5L}Rcy58;d8?+tpI_lIb@^lt z*3w$GE&-Wfrz+u*cpHc~q%dZ)7@4EXw@ux*Zk0EJqW!Iv)z}N%Wt!Wr+wIpjqWFfNd)xmsK!KlU|GB@t zTeSb#+h6&AEaj=P;m`5kE3Dod-S-=qy>Ao(6wft%CwH@be=s}KXZHZ3e_*hqXBOCz zmRl7Jrj};PTD0$fM(zxFe+Ql6v#QQNn{U3lIy}^KZ~9+tmE+Vg*Z*(7g#W$2!hcxK z)71aFNO|WtU4LyW{$>WG#@MuUku>hsvhnK^mRKS5wR8^=qbj&vOO=kJ^VWjxwobr} zD)^Uu&F|V%VH+XwNl=YEt6K!Ij9XTm;#NiYwQdrL_cZg;7K2OH)* zl%3;u9sl?CV>M`SlE$`e+qTo#Mx(~IZQD&_+iKjnadKjvbLaE@{RQ`0^JJdPnl*UO zTzg;FYZv-gtsgH9&T#UcaJe1TF8=ETza$XgYMNweYWMS=fFGwq^7dc)K3tE$O{rG- zSwMx-HM#J@{?ko^AasV6m`J1tz&5$uEP_#*Ozq?-=p3?p`FV?R-{r}hU1VP8vj_u=x9i%#4vBVB~RvYZix`09=!P3pN z%;jNsdXBTG2-lSFmr~C3_ZQcI!AqmLyi@RdqtkJgJQywJ9Xv2K^jYnvRd#si?wm-+ zc~rzGbfVnIA;{u~^`Uof=4#hB{Ee~prWoo@uXqV9;Yy#nF7Q*oignj^t3Be!l>+!A z!k>N4@5KonY!w)21pvFz&Ykd&1g32MvkCL>!blkjE?PJA{vo7kKg^EPN5+ zb9@ON+Rj`22n-AZ_obf5P6iTFf+DtV?gj&}7N?^hRnuD0)gJ-De$(DpzrpySA1rfz zAIhqrCs!*Eu>P!i6Qq`@Fp(C$!H7+5u|EfTe0{K=z^j|~>ovZ{a8@aC{`!63$>&qQpQ+Z>FEyelBpLFC;r<15Y(hpfZTnWmgz^S zp)M<&foiEY*4n_L&_|D~Zm>fCZ!sc*DbM(F7jW*@j_8C4SxgFN9~WQ2dT$q2J!XXD zCE@2$(>}MwKa{Lx9-zaarifXq_zQ~kqgPaB3g;B?_|Gd?P){!#6&@O=?a0J_U9+x` z-wI_O!?esikG^mgpmH)q448>;BNMQ4i|!OVVZeHRk~;A-d(PeE6r+~&>T?P(4eQOy z08-3z_wip@uj}Nb{fK?n6}4xAH*3-A+4W{4g4S(m>>?soS$b$R#EZ9_s6Iy=w3_4+ z(p;YIIs@bP2V`00f2?^3f$wn^bUv65W34Kk?^<^jK$J{G}xy^Uv%ujXT<#1X`c5VZ6z(k>aFt)7sYE51(2AA%l`5 zm!}JZkgq5Z7`X%C0Y4SZU~%b=#~wld*;;1wS){BG5RA%oip)|we$;HJF+tAH{W3}} za)X5}O8+!Z_xA=1L+kskfF?`6*#TJUr$Ad30Vf;JfPv?7c@gG2w3sGfXLRZvE04-+K z1)EkHOtWq?iQKF8J`|_8zI8NmE&`Pc4`mj`e3d|r+giQHmyO`oYChe;j-Pu&sTr(P zJ-H@&(r-qZI*=>P!2sLt_Vl2$&^9g!&+N{3V&ZMYng(%iI_|5g5`n5FW)i_P-%c^# z-(zkKcYUOA%K|Ug14g=_PaY-TXFX#1K)C9%LjsvbvbYzQfQD1dYbcn`tDOkVR%&CB z^515EXm$2kM1L4vMi&H^hGt2xmtUpt0yzAe%BMPai~CXMh()7oQ1eUz+sx`EYm!*+Uju67__w64Fl)_eqCVD$g)$-msYz&GcH zNU*Q>ubyVG!Q>r9oH7wSSUu0oja6jo)N=plDuok8?AxnO;nO-;kyYemBJk1kY3jL; z{$)-rKYOHa5W?SN=pK)D2?@Tniq1a__LXMN|6iZ-dZ={pObA4tBG~KclMA{F9}z+S zK368NfmC@60ij-iD^t)2HM@=p`^sQL+bi6ttVl!r<%az~h2#eRxa9xj5FEJw%byWK zMN%XK4T>+s4a^T6lwIwRw|rzMy{2i;$T7Z)k5{#BNiVSoAftU*MVCFVi^(oY*22f# z{*tv^_iG$)i!h`0_fPmysy3R?w$CwzrMtXBHb=05VXCirCaD_}tK(U&hnhw#==dZ! znfkcgS9=p<4a5p62lNHHEeB#f9Y3M*YO3R;C_3BHNN zHu4|naw$olHAi5yvyuMc)5xqYmj3QTsDrKU-3)mLlXGPKygq(mN5J#Z^ToyCr3>ob z50E-x%bjME_6f(^Dd(TZMF-28cGcWhPT*cPrR-mJwX27t^$0YaUZ8AchZ>t>lMP${SchX zc1-?8e8&Sl(SV1?t4a|W=`XHbe^~GQCrjI7q{g@n&1H=L_q(@yK)~(NdW7;PLIn7H zpOMmnR&kx6Y}Zk=S&e(Za)?-@JNY4k%!3h0g2$qd{DAkda~1)CM?*VwCUmcHEj~4( z-R@*6IhW1F<=NDgX(%(cTV0%sQa5Y2+BjEl)mr(id6Fz&@4#c($N2oWnnc9;i(Ioc zy|UBCdXnz>xyY}imm}jPn6v)-hp=$JRlUSAEOnllEdDSy&7+ghG51nGvVeWEp1;Sa z8Zr(3Tiz_2K1KH`ih z(eGj`EyLj&Md*^5x(f_I6-B&bY%A&lMRH5*qm@|?(Qavp|FIqH;12t}E7`7pdmi;JbGa+%7x zn?~Dp%n*F(M54l!gNd;bQ$NOJX*wA4Bm4ChyCq0*1=T!$Gi| zT;-|a+$nO|qGYjpo-q=o>YUlrv5~D0V=t>uQW%$odWT(+I!;MRkmHBk5y8irr z^S5Yyxc}#@4Edk4lEQcG(|v&oHtqX(d0x9?@&R?WZJ&WwU#|-i0(-Vztj?ciR^wlK z-sV=X0|h(S^9cLE&Mtm0prO-=k%*R*r9j-Qfox8x!PCMEmMF|Cs~=ZiFuZ+X7*k$D zrO2i74IPrL*0{@Lo zw%-^-QmM|kFw_-1w8aGDM5;Xzhk?b;AQC8aVOI?DvA}iGj7Xx2o?nr=3?Z%|Iac=s^V`>nswDuiK*C+l%g#X)<9PnT`YP z!WD82mKx=a9KYOosx&UFBFp(~>&aRZq~1fZm}Z=EtY*1veR;CvOfU28U?80+X2La> zmD#u?QH!wE|JE=Ib$d-@{~0&pq6dHJESr!?WDeaiNIEH4$SQ&z^0W!R#7ObdpY!~A zj6;kbA^Kyzz*DwHe;HHMuhh||Y7Rfb?T=!D5bBSma}fN{gBAbbgWaO7gC7-VNl?~r z;sD2_J{3lOW}EYM)R%L}h%46X^rucRXB;H=95~STQ_lAF^$ddbCYSobVA@finv{th z{?#0tM{T5saKa^uxwxdC*S3}lZPV!8De9vE)6!a!3wy=;kb z0|HM*An@j9gm0JR`%~Tr;KO)Qy^u<_0F|#PGU4tmOYzm^cSpU~D?{1qx94&HxRvnL z4a%xdlvRTLT=O&?^ytRyDa6D0J2ywUa}$aR;WpKrv5ci%r3h(IGNtbL??Z-|_+eF! z2LxJ3(Mb+G&1SwBlj~rbuDZAE5tnf)200r9KumUM`mq5w;J%sKNl|`2{w(fp6LM|M zr}f1510LR&8K+|1YaN_k;8DW&smSt%$UtK|Q#}CCrWz6Dvk&xJ zLMRd@h6ECAkD0j$X8#^BMQphqUzNa%j~H3Lo(m!NAiNGMKzXlo69n&NTfJ3vvKZv^ z2DUhT7yjeh`5(6YSl0z$a1w-^DH5O7G3Z7eG4$mdV?d8uuZl6cRRxU0_ba=*LMx(E zz26XvA}L*`i`ND-Pk~m`gR&4!UO2VicRqzR(?776m(f-2zA)2~Y?jQ(>KOy5OK9c^ zynef|`81Xn)#psu@&pF$>;)u&cZK{q|BpOud%SrUKd#J>OJj1JO0Qx43*s<)#(+ki zN@_wL291=a>!io~7PFu+GhXLuJSg`D$dD1FsY9e+&RlD%i{H zd+>cX=S7@arJDVAg8(#a)ek#z)e^>0ryjqM`vBv$8RGvX_`5u)+YfL5X!+78e%s7e zNopRpr&phaLwxypd~4RTTU$$E%8KJkP!U(NnaItGN#>AwgXl@Y9DQFA`YN=u3l$`u z6nOQ+s9_EBlM20~69_faM^Dau#>wthZ2`$F!fnE;DmxZP4-u>0x<+WRWPD zb}pGq47P*usP*FKNnKr%+l?EE)2}&!IXxH6?>dza1z*awTL>iFWKOnR=@&e}h})_` zKGYn=0l&@iyVtrZLF9ac&cL>x5+gI1^v6{z>42^XGj)^%g zEZ=;wvwahjSrfd;5Gc8W=2Bl!iH}7stV?~(@G@Q5_Q=|3(ZqR?;4Y#P8NvPq64q{1T1W*0y1^md4Z{W92O1F2%8KvPT- zuUk!vMlNXg{juM^l>UkOLj5AIJ7V1u(787<8+6m1xZ7Pu>p$mTe&9C*N@rhc5qgxF zlqN?GLy_#^QjDg;5BK@;uTZTk^T+!l=t-S|%%3QzZwp9oxk zlbE|b=x@Ur?40xi&%JjLzcOO59=+24N557Lnlh^2^URjy!B^!vZIPG_r-J}aa%Lh* z{fNhFF2P@BU+xpva3JX}p*Vbxu0&9pt@U=*;;JjGq^(UCNi@O=6{LxfS`x^n>&G7F z$gFb2z6t(UGGRvIzIPvuh(T@N?}v?|Gj@0XH>V7aT>kAnJISBjZ~iXoBIW|?KTy^< zlnhB|X$*;C;$_qG*URQWKl}&*Q`i2>5J6-rQKS!6pn_o!j)a(_?aQo6U7iE4{M%#f zWRGVk1(izB4r6uj6bH3AlYvrH_E#wx@(*C%D$^G8y+|w8Nojr?(Rq0&i8YQDqA&Kc9Nrn{-wm~J zoX$qjv(omcJG{~4XuVn^peg&MXZpk_(2)o|dww<_!u*%$UvI`+j^z|Cb_J5~`5O4Z ztE!EiV)%a{ai#4szghD#@2Hqci$A<%Nw3<-Va%%M)}Roam_)jnadD)!XW>Y1?MF{l zhlD_=P<_4Mjd+G~A%L?+xFTweOg1ZM1Af&`uls8LLxDUHGpeY~vHws0>J_7`_5NgU#Z4F=!qjysJ%>`)QaWbZt>TG*qNATI8GJrAGr>?8y_m7`h^ zSB2ORC6D8~i6IG|(~d1IGL22eox=;rW=8tJ;1utEQrn_(eRPrNPwMaoFOkVE@J?3X zPOYls4PD?|ERf6{YghHnv8h?Qi_``Bwh@=Oj6SN44Z9z_Ty<%ecC)5zb;yh;^E{ly zx7AE$opGmJgXXkLE~MC4r(3t-V|Yl4E>FhrUL$3=@+3p0NpmFxeR@zW+0OCBM+Y-E7t89)En^SSccI;+ja_XOX)QyfR=BtuOO;!)A>ivA=NietK!VB;d>I8 z7~rs?xMDl=?mLc{^kg|2_XKrP8kQl;7hN-AvocbR2GXeHcvX?~C~%s2RL&y|Sb_(cEMKj#lMS9&pqyFkjtuv@ zconJ|obxW4opF5Q?ILZUki~ob`O_1J?s^kHk(Pd>I7^vH%%fxSAWAq{2r>xZ$lGE% z8mI>B1`0Ob$;cId6Y~b6aV1JV2!U6~jSsh#$CGxWmv2jOQBAJI3RSarLE!bbwc~b| zQqyk%!gtz#)2!%S9AnZC)wSBze+$T3uB}mIrRH61-Iab`i%^PDtN}_I{tfSfT@co9 z$gh7zi|yBCEr-#fB=_feJh)%~rHldV--_~&z#mP#l>9#W4tVemHOp7^Fgq7n_`xsD z6e@M;Fi62!v=r8c*6y%j<~n~PBeBFssqZ$iGApcTh@6b0Mx%6hQnlQ>?Ddl$sjM!y2A)RTE;$e zhVEETp_%ylmE&Pj6rV~MS(kHAMG$tI$)s8=PWMkk&W=Yt<+uSs$ha%WysW=aDHzgD z4mpexGsiA@VzFj|&kW!l8RSv1!tUt99qy0P1HsAuY^Wu%13tg8*xzhzzAiZ@o&WWS zpu3P~UAIRWq&f0S*RB(w-5FnJZXJC1_u%7mV7_U?$FhqdOezSj5yr|F)PM&yd6_oSS*OrdjxNB(au(Y3X1 z2VhM6VYpe<`K?LpvQ3)Wu8v5h$f2Mcm3k?*^xJ_ks;g27Z~@9Qc|_ZE^1F)WN`hb- zH7+nZoV73<`fpsUi9uk+_o$R+=h0^Y@(VX8Ubr*8mE=5r`=T#P!y9gPKa2$jiiP{0ed5gem>G#;Nn7gJ~?EMt_p$J18q7WC3UKXt`G+TjAUE)zhmo|!E>jC^W| zP?MKN0r&651UX_h^pBAth#kX6SOszsuYovF~m`lah~dMV|(XSz)Lm66oPj?lQpfn5TU_5zi5JNI=Xlv&zPO4($qIo-R$T71^?iDmyQIe=>|&=%W}} z6Y$76v=ot0mRC_**ylN+c1UBJnbRswMpl5x^6OC8W%L}Uqi*4l&gT>-m$|vDihOK! z$G`6eVQ;WDzYUGCr7cg=TYQ_Eb&jz-Z}z-QZerQf z%l2aLtlwNas?y+UMF7=Qv^g?Yo<%>JCEFe{TrufU0KYuFbBZgqZ>i-V67(P`2L2qB zWo|3gCbiH{Vj(vbLNHa3%z<9^Ieq+iiJQ6n>}wLb;6jfE6B;XlWl-6*UjxV2c+Ium z^i9XMLkV3mxIGzL@lrBs$qLA%QNF!F3Dap7;)m9E=lQvs!jz{sjf!wpVEtw(fbN5l zU|MVajL-UoG_aD zS<6es2l)BQ)b;vKqH4uxw}McV`#emU48jiMm^z->JBTF>G+XPCCZ1R|auZC|`~-!nE6RXP@?iQl+N_w|#<0O=)x_>( zlDp7%U!r&>a-RyRxDX@uB;}oBrlhn;ohnF2X{UR^RuM4^t*Xi*zyXW-faafC^)^K3oijZo8*qh+KXt|+n^A^z%kn_$}mUqj{} z=ZD|yqK|!>AB}#1qVT5HJks~FW*R)-Ozk_JM=71`;5xlzmUW%Zp@)AdgV-}Lr6b~J*7p3d$Hen?MxzqonSnOaAmlo)VT)L^^Z}-ZNS2}>r;leg@cVe=3^Cw4anUV> z;I0_jJ7N&kS~#d*DFr2k6BtQpMB=T4wK2+%;6EDGTJo)VR;^^uk&Qvd1tVm|OJO8b z&LBu-k>u+~#?IJ((K6;rHQpC5y0}!$NIrk*|KgCW#sX|;j;Z5_Ny8s#j?paHFQ{Q@ z?KP&|mM3NW;Tf6OM|p13~YA-*&yifk&lwg}~>L zpl)W0#=xrAxy2N#6Bh5NO?Dn zN(he;w(4F6575D>nE_bQ!V-ttt8%CKN zk$@p=?3l?3-)eidCOCayiyL#)zXWn?#eO{~P-_B@sdXTV3oV&?1SPkWtlkF35I4ex zysK{ha?zi9@Od%AO2!dP`j!;W^x}O%^hoZ};A#-FR}AN_Zn)!GA}iah!Qa0Xii^9% z0(A)2^YzzzbFmEe5LDVG;9y{|J zwG{V3(Jt2KB%$QbYNj!T%&G!3u~7XU42l2D>#$@;_ZrlrE3cF74RM$^J%u9h9xtSp zeV)G!7v2JgKEe1Cx?$rzCW=LoyXXO}vW_yyfBo$|=_z!2a3QrhG9Z~#9DP(2ArRJd z@dP!w`=Z`l53oBHn1orGPt>VcJCNKM%DFvJEwJ?L( zEu|sR<~jCl!8_udrEJT5!wo|Mcve36MJyZ@f56Do zPfA*RNQ~#Sa-d_;q!tcWzP`MiqGoKRwrTAFr6V-g2QCzs<^^n7N4H3hehYqkQR4sC z20|!Gq$?%;g^4tn$ZSkvl~bmW*zn~njM*6Lz=)wjy*H>cQ#+5l`E{-?es8Yq`yZj*t0e<4JJJ(7Rr4dlxZfLFY>1~x>wLR) z$Dgt2cj2+^5=U0>-NG#wcrHYs6N0qE|1!n#)64wt`S8@3-<=2P&#$WvX^!=4%q@cF zsTT8`^dST!9G^Lia6e}Gz^-cN}=kBnJ=o8 zysvKtJ@a%ThO=F<9OLz#==qLwrN({P;4AWpke0CpU!B{RUw{80IV9t`L2Wo!gA_GS z&G@tYsIy#^LHzEB5aV@m<`Y@4lTdAUC z*Mv%MaY(!WrFX^POrEv4a&8$@PG-{jMxKCimUk|IEj-r}W@M|)h_AF{Q3i2B5o$*7 z^BIdMFb*Y)`X}aU*B8Ei-zn6pW6ksjpNQqCi6H!EBf53R`Lb!O#q; zFT)A+aBEy~VyFqQ)-GtRx888j1YD$jdDLsPm(!1$DG@L%ui~3*bMcQy{<_}hGq#7OcF5dLGU<=;k%Xx8LS6h5Yzk=50 z#IiZ8Zw{&E__xFC>j6{CZfeBEIjr_hHT|)cC8zlFF1jWp-jmHOPCcoO(@Qi@8r-h& zAk&H^4>=5sQD^7%5sS?Cn6f=@)iX(y9~;cwOWtn^zIQR6nApg2 zis}_3eLa;)dg=|}Kuq#|lbd?Hzq$FVZ`d{@6?tKEVl#Hf;umYbWd_~Y5UZ4Usl7a- zLyf-rUGlBC!GB?0C~fZb2~3Iek!^MK(dT6_4cxC;~>Z|MO$U4u8@z>lE59&q5= z6Zq1?Sa@>^^w`|jbFrpe|6$Mk_P2kr29c!EU;0W(tzxBZ2c!}}DoN2~N%$Dw# zwgYRdDh6TCe#z?z5FJBO4W$3J*%U#svptzss_n6AYbscNShN|1smDLL%zc>P31j8& z!3MTssOI|L`r4A4-nr-6Fi*R998@<9 z&I=&}UEia2JcC7v`oSl>&1-N3^tYXKnI$(L)Zb{tVIMM2dQXH&d^zVu8Av?Ezs5HU zz-d)3ilY*Q+b8lTu+2YgTvXbo-4~!oB@5YE#<$*x$83G8F#T8SumCsnY*V3`(^>Os z=~n!COOgN{HN9ECeMBRj<@B!I3vpRIR5eN5`KEtV?xRe|`yd37k)X$Hj*w&Ar6L0h zHZoR|r=O|5B6B!Wjy~v1ZuN{D1Xf$6JQIKKKH3T?hoQd(yWE0y&k6JFZ^7aMyx@eW z5*>m@4XdbDAWg{BgHuI=aZuHw80_arMB=ac*|BclptRYGq5B{iX<19*CNeODp9%nt zFLnQZl0geEm%11&g4w6j9;N{D4NENF0g_tn)wgz0cn(;xX?1)iG}wJx)9EztNuL)G zOo9yhJ7IzG5bptg!f1vva{l|$ zyap_2*4OxA7POt|%jpE9I<2vL4%TY)+Zz|s!HNcnh2T~SC~Mj2J*hL~uy(TDp}(DL zMJAt7tpwHD*sKE29ypmP+b7>tvuoj7ILvgE*1vFHeQn4Nk+XTmFkldN`m6*9R>b~g zg)U#MAr~`R#)P(2ePx(&-eVf#;la#*qF3*Xx6aK{DM5m`r`HIgJ;J-HV*XmCDrpJR z#Qifbf?vW)2&glJf&wcLOHC9vQD~HP&QQ|F|7S=5`A0Vg6{D||o@?kov??-}Y#3#? z0Vw6V`dl2qb-~;>Dvb2f@eVI79xBZABl+W>t|iAYt>L-SZ3apH)6uQ|x>*>c8W(Xe zGEUWP5U)jkCh`!B^y<=ChEj*9&r+JI3TFbN8&gl>y{t!inEAzH-}5O<6eXHatqvTg zol^=PXsx_@ZP?E4E+$t1O<;LhMV`k83N{c``-- ziq5__f^gUC*6&7MTfJ?r&<5CzEYX1X+2TeRdiTRlxLe`M{uxbNL3RY-UgjoXRMO_+SGBA#t00k?Jt5B_1 zN%Qda>qU);+LyRGZsaG5eC2{#;XMx#X$!I`x65YpuXq0Em|y&P$)~+=ig{b`?|sA) zW|k;a0|F1j&EKIgsT$a+tsq`EeX!75hM4*J%TrJorvA9j45&iR;p@whqh1 z0Q6DJ%}C6v_Y4SgO1rw^Wcah$gGt3G8eao5W>2tyEOI40H2gzG;2O4!i`EgXE0k6f zBS?RRIsOT^NS2IS8)VCCYZPC*ZJZD71dy?1GRwE2jq20?C%3}1>z5O6>flYu#l^VZ z)+#BrcVKxPozo2-A00irmMe0=`&J{Nj}`7a#)TOP130|!JjWX)M3VX}ZU^Do7- z%XldT>%~E)89Nxw?nL>6X3U%(dY-INrwp;w0qL^`=re!#LHjc!4W?W@nF(WiC%F{E z^Y<7HX!ceD31kds*U9NBajhJc8TJcmIBYz5Z4{Gu*=+vZjZ*(M8L~ko!80|PAM)uZ zT^%PmI<&YhY))-Z!YyH42)S9-TBPF`FftAKutcIOa4kz#SDXU_$ z*`|42BW7mfCb$~8T~|ddXw^=s8I!*4?79%>E0^uFc)6MR8s*vO!5l-5^|KB6_8r={ z4GQ0qIl-Gi;+0XDIn0SK_03>DhGQ`Azr6eQ#{x7U%>}trjo6Wc<{znI5=r*KCJBm6 z7)_&mi9xA79&^Z|4b8u($g)#%V({86`gaCh6l?oni6NQxOicfjQ=HV@4d`lRgRm>S zuYcZQ9_toRe|vq5o|tpt{OH9FuB zf^zet5YJOfY|}6IYCj2|O+d)}wo=GuZ%wH3>E8Y;_+YTU0W8Q{GR>}6P|0J^xb@ocBBxVWk^hCFlW$|Mj zsoNCcD4cv*{Q$$q!sEaH8qX<{-9H&%`bfO45xXpspu!V1GBE&l(-JOXk;hIw0PDN;JS-d){n0BM*8LJK=H&$2V;nt__?O~?k36Ya=6Yx!p%F%yb<*i| zSU%W)Ih?IH`eDm=%}m?ZB4eDT>rVXDLb^+Zm=&@%WnjZgNat#pYBk^**6Rb}*67K6 zliK-i(`Gvx5#L^neaVQnjK`U;lVV)>@YQ;+J-?}XUmvB`|9%=FI?XVwQ+_oI(X;6I&d6HFtgxBF3@N+XXY*#3M(^dJED4B#XBlG|MP z`{p)1_*4xiE%~3E2v^;%i_$q9wGYaQ614v;RT|H^wd0knVaxve&Jr8L+OkQO_7oR5 zIT&9Dy=KI6N)7S6K#u*6W$yT;FZtD~4OHQ#whSil=m7S?`^dc#w?#jdfm}LMj;jkS z{MJ5d{OQ(X!s&>=V8|cbd2k47BEN7~9#xr|YTJ2Nubs}-Z0mm5V}S3@+YPoKW8vem zOkhFR4@%L`eVdzSfkekIYUc^~x92z%?uoGq6n=y`I46KBsitKOR*52|HPF40_PcxIvqUz|rjB^T^gFEfR zUah|b?+VgRfcYafpPkTvhZ`qf6BD9pf>isZIHGkD4@e7jG>Qy>vODfCgCaTGO^FPZTj`Uv z2}wpW8Q0qK!PmDrt(t74oW-%~c*BJgZHDl6%X@Yo zhGTKwj0Bsn?h^-*Bfq=0w+$DAqN6=hF7%SwZbVb{anp^Qcyv-T=ShBEKyn1H6qO*4 z%+SdeWMf$@4b*$&A~sI3oE$g70Y4$D?fOCzTvI053)eszWQWMX!oG9eT9f4I4!V%S z;)&_0xhTsH2hPZ5K3`@H4tW;tL5!g=Q}08>Qg#-GpE)sRbg)xIKpCzP=cXFo6)B!< zfQOWsk6%eyS__Sxqy9zp==+h+q)D_w#DNbM<9Oc*huY!*g{l>J%gY(+V zl=#SlPms~YSU@MQ122))CDfG}tgRlN>HBi|fDa(q%ggN!11|^&u`j`0JtcMEwGaX0 z>I3jpTephcIt4_lVK3Km*^;#?od&|F@#k~~(qMexa2r$QWe;4i=1T87=_l0r=AGJR ze2GQBRT>=tNW{B2{XPR5aYi)Rqm* zKGf!o1V8cKN>@|@1D{P=PQY}re?nnlac}6}3Q|(k-V0LdKu@Mbl#d)3CUx7e737S- z?tC^G;Vfg5Wy3He)`FsLOoq@y52<3fd&T6nbU*c<;%X({Q$BeSaZ^`L68?{I)`^6$ z&4MK;2g&+hI$*eQVl-?;Vvt5S3tvd3dpzbDXcxx|J2LS{F7PaZ`_)V4iPVZOBf~|S(3&8-doqK+&e$o8s zyN1IX2Ff3j1vNYmd`AAzTPl@jIa1u{Cj*a83ztS%CJq_oRb16~Wpqn#czGPvE!nuV zM&sPSun^I>x)Bi3Rx?4_i<+3bwR?avu%C>7oK?v)@qXU?Lgd`Rv>A-{U+_Um@`v`5 z_c{2EMHzBCbRz>xe66xg;)5SAG^iO9*fXVXM}80OkXP*xgrb9ha3vr-vB@0TTlfkr zX5FKoWfn!3Yjfb`C}LQ#L0qL=Gr_@n1M-&0MkTd5G=3=|VHAwjv$J;-Y#V(-Zc$-0 zwV|i3N$z0GbWUlo8dcQFcEyn@GrZxpSyWtQJ*To*y4p`OeGud5;n%qM?jC1sg+F!L zVHN9_b2z%n?NbyRnSnyY_@yxZ4YmCIH!>Im z`JJC)hJesQq-iS;1Zt+L-?o@odqnztptzUdT5gxAc$=B-l_)RyJ1w`??719+Kjm2R z2UvY35n64fWy=a}yK6DpOH3P6jtEG32DJpUWv@Eo5=@&b38O*9)*SIZa2$%6&fmO* zFSTlF(EL}fdOl~ld7jC$Y=cTSQ#?DMjR8ZK`h37CYKI=TUQq4KVK2(r{-oxkQD-6- z)IyvVB4w@eZX=9Y$`d$NiH@*eYYXg4UG_|zR|kHA7Bsf~=sUQF!ntSK*)319-MxNy zD?91X^bHBvEnjikI^PU#shacZwUoSn74-JghXy^q_e`nl+nnDdKGHqyUmEtEpV_mY zaU1$aQKjRiU09(j-ZZWIt=pT`IWlPC*< z8`AHXw)$-M0S%_$y6d#}zSmyWE8*)qd@HbnNDdI}lXne-GC_OU?1I!#xFWtoYBWDt z*@jHF@1~S=4E&;lV_dZ_7WT;uT$ATE37`>S9#^->Da@!$q8HyGF@jebNywFs9i6#? zoelc6GV+&RQCE9b`=s8@1KX-2ucDq`HqS{H?v1mc3m6DWm27eTtnaKmHobzh8^LFU zUZ@?QT{PfDVh6`mrg=A;k~3+NH`)oQC5Ftuf5}RjH$8+D)}NnMff*Qdb!^H0ha}t? zsU?Bme1xCArL_*1A2HD+sD~^NnzQH2t@arBL-1#M+82^oSGYhN&=&6yoH^t zWu!CiLSu&_5wD||>oKpRgiAAaFokm_`h4(|x~ahp9pWI#rNlW{Uf)|a?|@{WvVE#g zz&DoP2_x#DiMxj3NO*g&Z$IN_nUdKEbbeH0ywfYtcVi{0NIW$MRz3Np-w3`Y%yVzQ z1rr^vlM2%=G6A~;5TC7uzPpr*%@@v5Tg$2MeW<(6V4&RKlG7F_mzQ_%e`b!=V<{s< zoemeo64Wpc#w_U`bB*&6i`b9WvMo^Ajg54zCx5;WPS{lpEB;QNP0mpDAHwq^NF19k zc-|=#O}!bYk6K7oT!-RQi+W_?mTv7I2o0{RW40O%*~~Y~3RM>Ax7WGK_q0X1xOtk=gAW;2b!lEOj@Xq60mJ`u5XSx!T)83?Wc@7qTj?pw~ zFw|2>8KD?&7C2vxJ6AF$YmmA7b|4~cic*=GJQnh3@x(O~qk8t*M&b5ObIYPs=EzfjQJ0W-C=E_?yC#gk@(Azg!ds2bM^P5sAu zI{9>YVL5bDNY#6}X?It3rPJ!q*3=P)4w7?K7j%*Uy@D;5cfDUNJF`>d8P$T;k9nQL z+PPkQhuX;B`;Ir3QsZ>IDc5!`E=RU6gg>0rmHg8SQCDx4*CKvJbsFav8AkK*vox)gX+!s$cE2w z$ZOwy2iE)F%D=5JJAoE@y}?V$R^SfJ7RbvuLt>t__#AzL&ZxW^=-HiXtp>c@mZhYo ziIxd%C;xY$KQ(V^GI25b&GogiNc<`WsS;7JJByYTg?dEEw|SPh(gH*gDL&P@yDEtT z0JT@xJV|I?k(Y=FwuN5l$kX4-z3&-`gw%~yv(2cTxi5d-N4qkMhgvAil3zT3EeUAP zC0njQtlIl9MixINUj?>rNO3i2=`p)|Dk76m}ZPx_UHjPue{SX|So2u`OE902bK$ph& z1I$c1-7of5=7zUoq5hp=W-C4}&YE_8xNjN>?;r2H z3q~R^I!RM_56aH=P=h|3weU|6J+H6QGDrXMUlKWRVU5e+=fat0W_aga^&75`{KQ$W zt%*4FVaB9RcER%`%P@YN7$)QAXcJ;4OgK_en{adN5zB`>1#j@-Z^G-OTsNdVL0T6z zP_+j7cLkQeIa6kuEbB&nXYoc4Yt5LInJ$T=^vP=K{h8*4T-s+l?TO1;Mh8<|`n$L- z;y+%754qz!dY@#uHa(mIyrp*f0;LppKPA82-!H!8nk%J46^=6nI2y_oLPDm9tgsR( zyC*D&mzq$FW%S~w_ECQ2T2JXh;46_gu82I0`d_Qry;?@{UTXAnX#SPI9_0wqm*-8rH)!?s8vX2X4NkvTralp%4E+iJex(myR@ODd9c26K>$~G`2>$`BXj33P_#?n`Q9rS~zqX2rq7lJ?a#Nndx4kjqKQDhDC9u zBSblyZo;JvHVdmcF=+hS=}&BykaqbBbkUnIV*Gd=+DHgLHlk_|eq?HqD9Op~YBqYT z=yI=6O)`o$H|2VGuj=@Y&yQx`ZjhowgTw1d`nIFCQ17Zz&$_A~iOB+~{`CjO#QYuR zwpp0|sLk`Pi-OjXjT6@VrhRF6@5R(9V0KV`lEZ8BMFSrrkydQT;A;w3*0I>yU1_+* zH4CDZlzHSS>dtUlwEal09 zofq#0z*cgKH+t`}3b*dR$@N!+`JFQP25z-{=HBYFWTbxIx3l9PRMttl8SqbZP%=c} zU)%_rKTx`pTtOi~QtAMIZwKZn8Wvz;o5%bO1Tm_zpEJr=*%7pDJ=ZR4ZyLGZeM~Dn zXg zCmP$)vMaOMC??eb{ z?;*46bMCn5Zo<_D`&t9bzGQ(?lUhD!&vZ+Vgl?aYi$1qzA8-L{J>k?zpJ{l{+^{Z7 z5RpNrfO_M6w&@%A4g1V)ot;Js!7#J4q%)h4Mq)#Ni@}todtjBDah>;UXN!4C=eX`3 zwDwuY@bW!?r*&BWXGOx^?)jR?B!9=${og2mNREZ)z?EB{<|;Fc548J7lWyTpi(DSL*KpJU$yw*2o3Fqtqlo$CU};q?$Z{99!{MFwL81$= zmQHCS$*+y(s!Gzye{w`?{)+Tjpi_SS?|oM(e^+j*5cy z1Ek_(C;3683LcfiS{YSgPBXoEjH5z;efpF1Vn{oR^>h%itCmED>}L-R7=R zCUdmI=bVOl4gCmTi(OWSY=_~X4`yiAH`FI6XRT*I8(09wzqN2(!gP*m!zoK4rb?gaUa~B!ok9l<;bh*u998fGXPIyWBU6#g6 zjG7~!V|1}sZ@py~Qd^`|{3nI(Mbhj}m!xW`7^0BF8FjK!YeiXP;P5YXDpOiSw7(TL zshebqYw?3JWE;qmvL0*@bavI?LR?9X6}hPveN~FKUFu(f*z)ZfZ=d3IwuRTAnj3kg z=JSb}4@f>|P>_m%D-3<3Geq>dURf!yQsstQyXZPpm=pfl|8|$hDL-URqsFKUS1y>U zW@^XxONdcNYUj}~cIPZ+7RLyFM?Y6(-v?cL7k5s)#x2mx4e#@tnZ|#Pggh>-IsuDF zZ`QiATv|m|_y<6FX-&Eml&{Xp?kp>#7HeHur?2&@)bW~As@n%we;y-{CHDQO457K{ zu!2<|6GPL{evNR6xt)(-z*O0`hY0MQC1LF8B8xjn7!dM zzS6?5;gi^q)gXV?s&`usuF&?pEcjK_Iial^IHn#PeE(N!lBp-mU3YUzSA)^c;(np! zQLGu9mfFWw*7i>Nd{3qXf!cUx31{}k@8WKRI>wmO1jkK=_~Xd(DGMV~)mw4;IuI3g zO|P8^1xH+{lLQA~1j3Vh`8<&UL6b}IR9y&HVU4h2D04b+Znu>#5NWM(x{R&xOzAvmG>YP*>#ZPZcy|toaUtK4k~?%Tg_9?$~D!Qty5%b^?5E z0bwnsM!(Z<)nr9S*1EpZCstqM2LzZ?9D!HpkWe$k#_4(mgpdeYI((6jO>M@zY08lc zsq$1%?bO2stait($zNEXXb*H3Ruw-;MO+&`nKupW24OO!WfUci29K7o@pOwu=|WGk z@MhtVKMqXQJ+eo)}5UE+yFoK=g;Hp*mR=6fHyrkodQ$q`;>W?Wc6l> zx%CbwiFv=!;@dRIZkfcC>pxItTQjN0<9hQlfAz-Fwzi3b8 z#Jm5V=Zzf;NBnaXmK{oEJ|Fx#E3~+?B1J~fC|nHQr9l$~t%RFK0`G>0A-|C!-V{Z# zY#o(TI{h`1A&X?sC0v2TWcxvDXlV2XuXz69uO|Iuud%Z4yk9@{U!2i=gvhjZSqQ>kukLz;3&8RE zG`CK`SBT|54y2o1i;;`!;HPh&QlhmLp@Y@nytdncmHsz`$*d<BosOEh z_KxiBnSD75+|j>B7A6s??gj^cH{m#HA~?xcsZTYShzwF2dmR6LJ_3WkEaCq?9?HL7yq1k4BHn@#ZbmL1*HLp_LvfzfB(vy326;*RsX0} zDiG7^ZKC^W_{QFRf+Z$FyDOMQ%+HK%rydn>Uw1DwZP_0=T!d$=)}wKnG#NRr7x0 zL_0qRN5Pd+CB@Daxs!b6F|nCAKmk56>w2WViH1kIMKcGbM!>H!7ds0t5q~0??vrHy zsZN+zt4B|sqQYX2!t|vqF=6~EL;9>^sQbt}#IlCvn;|>|f%*=b?&$DJ1;r`qam~(& zcw30kQW1piPAy;XUW9#3zA|R1Gewpp&Tc6lr<&F97anwtCGQd*JnFfb=5fnMg_;!; zFXC5lW<|~*h`s0f{lH64KDm>El$vk1VzBD8ubniRz%Wf%IQG06vn{+?OLWsg_?b(0 zo5D}HYz6DA@M3TA<8$L83Z@X`F0MG43>ecWP|yKEDwK*-d0wPAs-R>CpQPsBWtlor z>qAfH$#~ZF9e&0^JQL@uK@IcB7Fo;9gS+A8drw<;x3Z2XBtatHZJC1**Rs%-=&wA{ z?wwz_MVzN(T;u?|1zUs(1QM>JU#Xxwu;Nv*b6)tCNuHFNvED(JE@C-E-rd-737N$1 zojAdw9-LtXDBaAuiZHfs8ar)sWlV`a1BX(Xv1o9TLKlpM^dT?!J`}rFIpq8!?-duE z)T(rhJm#i}*Hh0eznpdXqO_iK{swqOf$Xnq9tL$$6jK+>WOffxisN^ZJnx1w0aA&X zGCrMgtzm)@zq8dGpxLdRaJEHTJk)qU3lI!hvNFJ%4-5o{vFOoIE2N65jCYzOXeSVy z1JA|fMj>-mz11ko5dM29+dW4-Ð!5G&5V#z(_S77q>J5KkVt(O!b3_a(?OWbK%X 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 P00960Wu`9u0E{O9gPgs2 literal 0 HcmV?d00001 diff --git a/assets/percona/psmdb-db-1.16.3.tgz b/assets/percona/psmdb-db-1.16.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..6d0c42c429dd6b1a5176d1207de9c4f09b08312e GIT binary patch literal 13279 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 literal 0 HcmV?d00001 diff --git a/assets/speedscale/speedscale-operator-2.2.203.tgz b/assets/speedscale/speedscale-operator-2.2.203.tgz new file mode 100644 index 0000000000000000000000000000000000000000..6ef52fa0ca7725694f2232e60b98152652b7259c GIT binary patch literal 16667 zcmV)VK(D_aiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMYed)u~>IC}oQ`V?5D`^4^wlI_GvS9^N)so}HbYoo7#NpFe%R_qUzh{oSX} z{)TqmPxGsvLMkl&wsY^c>Ye*c9?Te5SW(VozlBhY6;AoI8)KzX(xto?6QSsYlBADv zEEFT6u~bWMb$ob}P;e|(L0ySvZ3JJHVL#`1!s z1WRIDY2e)!≷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 literal 0 HcmV?d00001 diff --git a/charts/codefresh/cf-runtime/6.3.52/.helmignore b/charts/codefresh/cf-runtime/6.3.52/.helmignore new file mode 100644 index 000000000..bc71d4240 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/.helmignore @@ -0,0 +1,3 @@ +tests/ +.ci/ +test-values/ \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/Chart.yaml b/charts/codefresh/cf-runtime/6.3.52/Chart.yaml new file mode 100644 index 000000000..b2f664136 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/Chart.yaml @@ -0,0 +1,28 @@ +annotations: + artifacthub.io/changes: | + - kind: security + description: "cf-docker-builder image upgraded to 1.3.13 with security fixes" + artifacthub.io/containsSecurityUpdates: "false" + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Codefresh + catalog.cattle.io/kube-version: '>=1.18-0' + catalog.cattle.io/release-name: cf-runtime +apiVersion: v2 +dependencies: +- name: cf-common + repository: file://./charts/cf-common + version: 0.16.0 +description: A Helm chart for Codefresh Runner +home: https://codefresh.io/ +icon: file://assets/icons/cf-runtime.png +keywords: +- codefresh +- runner +kubeVersion: '>=1.18-0' +maintainers: +- name: codefresh + url: https://codefresh-io.github.io/ +name: cf-runtime +sources: +- https://github.com/codefresh-io/venona +version: 6.3.52 diff --git a/charts/codefresh/cf-runtime/6.3.52/README.md b/charts/codefresh/cf-runtime/6.3.52/README.md new file mode 100644 index 000000000..23ae7e1f4 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/README.md @@ -0,0 +1,1228 @@ +## Codefresh Runner + +![Version: 6.3.52](https://img.shields.io/badge/Version-6.3.52-informational?style=flat-square) + +Helm chart for deploying [Codefresh Runner](https://codefresh.io/docs/docs/installation/codefresh-runner/) to Kubernetes. + +## Table of Content + +- [Prerequisites](#prerequisites) +- [Get Chart Info](#get-chart-info) +- [Install Chart](#install-chart) +- [Chart Configuration](#chart-configuration) +- [Upgrade Chart](#upgrade-chart) + - [To 2.x](#to-2-x) + - [To 3.x](#to-3-x) + - [To 4.x](#to-4-x) + - [To 5.x](#to-5-x) + - [To 6.x](#to-6-x) +- [Architecture](#architecture) +- [Configuration](#configuration) + - [EBS backend volume configuration in AWS](#ebs-backend-volume-configuration) + - [Azure Disks backend volume configuration in AKS](#azure-disks-backend-volume-configuration) + - [GCE Disks backend volume configuration in GKE](#gce-disks-backend-volume-configuration-in-gke) + - [Custom volume mounts](#custom-volume-mounts) + - [Custom global environment variables](#custom-global-environment-variables) + - [Volume reuse policy](#volume-reuse-policy) + - [Volume cleaners](#volume-cleaners) + - [Rootless DinD](#rootless-dind) + - [ARM](#arm) + - [Openshift](#openshift) + - [On-premise](#on-premise) + +## Prerequisites + +- Kubernetes **1.19+** +- Helm **3.8.0+** + +⚠️⚠️⚠️ +> Since version 6.2.x chart is pushed **only** to OCI registry at `oci://quay.io/codefresh/cf-runtime` + +> Versions prior to 6.2.x are still available in ChartMuseum at `http://chartmuseum.codefresh.io/cf-runtime` + +## Get Chart Info + +```console +helm show all oci://quay.io/codefresh/cf-runtime +``` +See [Use OCI-based registries](https://helm.sh/docs/topics/registries/) + +## Install Chart + +**Important:** only helm3 is supported + +- Specify the following mandatory values + +`values.yaml` +```yaml +# -- Global parameters +# @default -- See below +global: + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used '{{ .Values.global.context }}_{{ .Release.Namespace }}' + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used '{{ .Values.global.context }}/{{ .Release.Namespace }}' + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace +``` + +- Install chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace codefresh +``` + +## Chart Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +## Upgrade Chart + +### To 2.x + +This major release renames and deprecated several values in the chart. Most of the workload templates have been refactored. + +Affected values: +- `dockerRegistry` is deprecated. Replaced with `global.imageRegistry` +- `re` is renamed to `runtime` +- `storage.localVolumeMonitor` is replaced with `volumeProvisioner.dind-lv-monitor` +- `volumeProvisioner.volume-cleanup` is replaced with `volumeProvisioner.dind-volume-cleanup` +- `image` values structure has been updated. Split to `image.registry` `image.repository` `image.tag` +- pod's `annotations` is renamed to `podAnnotations` + +### To 3.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release adds [runtime-environment](https://codefresh.io/docs/docs/installation/codefresh-runner/#runtime-environment-specification) spec into chart templates. +That means it is possible to set parametes for `dind` and `engine` pods via [values.yaml](./values.yaml). + +**If you had any overrides (i.e. tolerations/nodeSelector/environment variables/etc) added in runtime spec via [codefresh CLI](https://codefresh-io.github.io/cli/) (for example, you did use [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands to modify the runtime-environment), you MUST add these into chart's [values.yaml](./values.yaml) for `.Values.runtime.dind` or(and) .`Values.runtime.engine`** + +**For backward compatibility, you can disable updating runtime-environment spec via** `.Values.runtime.patch.enabled=false` + +Affected values: +- added **mandatory** `global.codefreshToken`/`global.codefreshTokenSecretKeyRef` **You must specify it before the upgrade!** +- `runtime.engine` is added +- `runtime.dind` is added +- `global.existingAgentToken` is replaced with `global.agentTokenSecretKeyRef` +- `global.existingDindCertsSecret` is replaced with `global.dindCertsSecretRef` + +### To 4.x + +This major release adds **agentless inCluster** runtime mode (relevant only for [Codefresh On-Premises](#on-premise) users) + +Affected values: +- `runtime.agent` / `runtime.inCluster` / `runtime.accounts` / `runtime.description` are added + +### To 5.x + +This major release converts `.runtime.dind.pvcs` from **list** to **dict** + +> 4.x chart's values example: +```yaml +runtime: + dind: + pvcs: + - name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +> 5.x chart's values example: +```yaml +runtime: + dind: + pvcs: + dind: + name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +Affected values: +- `.runtime.dind.pvcs` converted from **list** to **dict** + +### To 6.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release deprecates previously required `codefresh runner init --generate-helm-values-file`. + +Affected values: +- **Replaced** `.monitor.clusterId` with `.global.context` as **mandatory** value! +- **Deprecated** `.global.agentToken` / `.global.agentTokenSecretKeyRef` +- **Removed** `.global.agentId` +- **Removed** `.global.keys` / `.global.dindCertsSecretRef` +- **Removed** `.global.existingAgentToken` / `existingDindCertsSecret` +- **Removed** `.monitor.clusterId` / `.monitor.token` / `.monitor.existingMonitorToken` + +#### Migrate the Helm chart from version 5.x to 6.x + +Given this is the legacy `generated_values.yaml` values: + +> legacy `generated_values.yaml` +```yaml +{ + "appProxy": { + "enabled": false, + }, + "monitor": { + "enabled": false, + "clusterId": "my-cluster-name", + "token": "1234567890" + }, + "global": { + "namespace": "namespace", + "codefreshHost": "https://g.codefresh.io", + "agentToken": "0987654321", + "agentId": "agent-id-here", + "agentName": "my-cluster-name_my-namespace", + "accountId": "my-account-id", + "runtimeName": "my-cluster-name/my-namespace", + "codefreshToken": "1234567890", + "keys": { + "key": "-----BEGIN RSA PRIVATE KEY-----...", + "csr": "-----BEGIN CERTIFICATE REQUEST-----...", + "ca": "-----BEGIN CERTIFICATE-----...", + "serverCert": "-----BEGIN CERTIFICATE-----..." + } + } +} +``` + +Update `values.yaml` for new chart version: + +> For existing installation for backward compatibility `.Values.global.agentToken/agentTokenSecretKeyRef` **must be provided!** For installation from scratch this value is no longer required. + +> updated `values.yaml` +```yaml +global: + codefreshToken: "1234567890" + accountId: "my-account-id" + context: "my-cluster-name" + agentToken: "0987654321" # MANDATORY when migrating from < 6.x chart version ! + agentName: "my-cluster-name_my-namespace" # optional + runtimeName: "my-cluster-name/my-namespace" # optional +``` + +> **Note!** Though it's still possible to update runtime-environment via [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands, it's recommended to enable sidecar container to pull runtime spec from Codefresh API to detect any drift in configuration. + +```yaml +runner: + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: true +``` + +## Architecture + +[Codefresh Runner architecture](https://codefresh.io/docs/docs/installation/codefresh-runner/#codefresh-runner-architecture) + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +### EBS backend volume configuration + +`dind-volume-provisioner` should have permissions to create/attach/detach/delete/get EBS volumes + +Minimal IAM policy for `dind-volume-provisioner` + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AttachVolume", + "ec2:CreateSnapshot", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteSnapshot", + "ec2:DeleteTags", + "ec2:DeleteVolume", + "ec2:DescribeInstances", + "ec2:DescribeSnapshots", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DetachVolume" + ], + "Resource": "*" + } + ] +} +``` + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM role + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] +``` + +2. Pass static credentials in `.Values.storage.ebs.accessKeyId/accessKeyIdSecretKeyRef` and `.Values.storage.ebs.secretAccessKey/secretAccessKeySecretKeyRef` + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" +``` + +### Custom volume mounts + +You can add your own volumes and volume mounts in the runtime environment, so that all pipeline steps will have access to the same set of external files. + +```yaml +runtime: + dind: + userVolumes: + regctl-docker-registry: + name: regctl-docker-registry + secret: + items: + - key: .dockerconfigjson + path: config.json + secretName: regctl-docker-registry + optional: true + userVolumeMounts: + regctl-docker-registry: + name: regctl-docker-registry + mountPath: /home/appuser/.docker/ + readOnly: true + +``` + +### Azure Disks backend volume configuration + +`dind-volume-provisioner` should have permissions to create/delete/get Azure Disks + +Role definition for `dind-volume-provisioner` + +`dind-volume-provisioner-role.json` +```json +{ + "Name": "CodefreshDindVolumeProvisioner", + "Description": "Perform create/delete/get disks", + "IsCustom": true, + "Actions": [ + "Microsoft.Compute/disks/read", + "Microsoft.Compute/disks/write", + "Microsoft.Compute/disks/delete" + + ], + "AssignableScopes": ["/subscriptions/"] +} +``` + +When creating an AKS cluster in Azure there is the option to use a [managed identity](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) that is assigned to the kubelet. This identity is assigned to the underlying node pool in the AKS cluster and can then be used by the dind-volume-provisioner. + +```console +export ROLE_DEFINITIN_FILE=dind-volume-provisioner-role.json +export SUBSCRIPTION_ID=$(az account show --query "id" | xargs echo ) +export RESOURCE_GROUP= +export AKS_NAME= +export LOCATION=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query location | xargs echo) +export NODES_RESOURCE_GROUP=MC_${RESOURCE_GROUP}_${AKS_NAME}_${LOCATION} +export NODE_SERVICE_PRINCIPAL=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query identityProfile.kubeletidentity.objectId | xargs echo) + +az role definition create --role-definition @${ROLE_DEFINITIN_FILE} +az role assignment create --assignee $NODE_SERVICE_PRINCIPAL --scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$NODES_RESOURCE_GROUP --role CodefreshDindVolumeProvisioner +``` + +Deploy Helm chart with the following values: + +`values.yaml` +```yaml +volumeProvisioner: + podSecurityContext: + enabled: true + runAsUser: 0 + runAsGroup: 0 + fsGroup: 0 + +storage: + backend: azuredisk + azuredisk: + availabilityZone: northeurope-1 # replace with your zone + resourceGroup: my-resource-group-name + + mountAzureJson: true + +runtime: + dind: + nodeSelector: + topology.kubernetes.io/zone: northeurope-1 +``` + +### GCE Disks backend volume configuration in GKE + +`dind-volume-provisioner` should have `ComputeEngine.StorageAdmin` permissions + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM Service Account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +2. Pass static credentials in `.Values.storage.gcedisk.serviceAccountJson` (inline) or `.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef` (from your own secret) + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: | + { + "type": "service_account", + "project_id": "...", + "private_key_id": "...", + "private_key": "...", + "client_email": "...", + "client_id": "...", + "auth_uri": "...", + "token_uri": "...", + "auth_provider_x509_cert_url": "...", + "client_x509_cert_url": "..." + } + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g.: + # serviceAccountJsonSecretKeyRef: + # name: gce-service-account + # key: service-account.json + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + iam.gke.io/gcp-service-account: @.iam.gserviceaccount.com + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +### Custom global environment variables + +You can add your own environment variables to the runtime environment. All pipeline steps have access to the global variables. + +```yaml +runtime: + engine: + userEnvVars: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: github-token + key: token +``` + +### Volume reuse policy + +Volume reuse behavior depends on the configuration for `reuseVolumeSelector` in the runtime environment spec. + +```yaml +runtime: + dind: + pvcs: + - name: dind + ... + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +The following options are available: +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName'` - PV can be used by ANY pipeline in the specified account (default). +Benefit: Fewer PVs, resulting in lower costs. Since any PV can be used by any pipeline, the cluster needs to maintain/reserve fewer PVs in its PV pool for Codefresh. +Downside: Since the PV can be used by any pipeline, the PVs could have assets and info from different pipelines, reducing the probability of cache. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,project_id'` - PV can be used by ALL pipelines in your account, assigned to the same project. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id'` - PV can be used only by a single pipeline. +Benefit: More probability of cache without “spam” from other pipelines. +Downside: More PVs to maintain and therefore higher costs. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,io.codefresh.branch_name'` - PV can be used only by single pipeline AND single branch. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,trigger'` - PV can be used only by single pipeline AND single trigger. + +### Volume cleaners + +Codefresh pipelines require disk space for: + * [Pipeline Shared Volume](https://codefresh.io/docs/docs/pipelines/introduction-to-codefresh-pipelines/#sharing-the-workspace-between-build-steps) (`/codefresh/volume`, implemented as [docker volume](https://docs.docker.com/storage/volumes/)) + * Docker containers, both running and stopped + * Docker images and cached layers + +Codefresh offers two options to manage disk space and prevent out-of-space errors: +* Use runtime cleaners on Docker images and volumes +* [Set the minimum disk space per pipeline build volume](https://codefresh.io/docs/docs/pipelines/pipelines/#set-minimum-disk-space-for-a-pipeline-build) + +To improve performance by using Docker cache, Codefresh `volume-provisioner` can provision previously used disks with Docker images and pipeline volumes from previously run builds. + +### Types of runtime volume cleaners + +Docker images and volumes must be cleaned on a regular basis. + +* [IN-DIND cleaner](https://github.com/codefresh-io/dind/tree/master/cleaner): Deletes extra Docker containers, volumes, and images in **DIND pod**. +* [External volume cleaner](https://github.com/codefresh-io/dind-volume-cleanup): Deletes unused **external** PVs (EBS, GCE/Azure disks). +* [Local volume cleaner](https://github.com/codefresh-io/dind-volume-utils/blob/master/local-volumes/lv-cleaner.sh): Deletes **local** volumes if node disk space is close to the threshold. + +### IN-DIND cleaner + +**Purpose:** Removes unneeded *docker containers, images, volumes* inside Kubernetes volume mounted on the DIND pod + +**How it runs:** Inside each DIND pod as script + +**Triggered by:** SIGTERM and also during the run when disk usage > 90% (configurable) + +**Configured by:** Environment Variables which can be set in Runtime Environment spec + +**Configuration/Logic:** [README.md](https://github.com/codefresh-io/dind/tree/master/cleaner#readme) + +Override `.Values.runtime.dind.env` if necessary (the following are **defaults**): + +```yaml +runtime: + dind: + env: + CLEAN_PERIOD_SECONDS: '21600' # launch clean if last clean was more than CLEAN_PERIOD_SECONDS seconds ago + CLEAN_PERIOD_BUILDS: '5' # launch clean if last clean was more CLEAN_PERIOD_BUILDS builds since last build + IMAGE_RETAIN_PERIOD: '14400' # do not delete docker images if they have events since current_timestamp - IMAGE_RETAIN_PERIOD + VOLUMES_RETAIN_PERIOD: '14400' # do not delete docker volumes if they have events since current_timestamp - VOLUMES_RETAIN_PERIOD + DISK_USAGE_THRESHOLD: '0.8' # launch clean based on current disk usage DISK_USAGE_THRESHOLD + INODES_USAGE_THRESHOLD: '0.8' # launch clean based on current inodes usage INODES_USAGE_THRESHOLD +``` + +### External volumes cleaner + +**Purpose:** Removes unused *kubernetes volumes and related backend volumes* + +**How it runs:** Runs as `dind-volume-cleanup` CronJob. Installed in case the Runner uses non-local volumes `.Values.storage.backend != local` + +**Triggered by:** CronJob every 10min (configurable) + +**Configuration:** + +Set `codefresh.io/volume-retention` for dinds' PVCs: + +```yaml +runtime: + dind: + pvcs: + dind: + ... + annotations: + codefresh.io/volume-retention: 7d +``` + +Or override environment variables for `dind-volume-cleanup` cronjob: + +```yaml +volumeProvisioner: + dind-volume-cleanup: + env: + RETENTION_DAYS: 7 # clean volumes that were last used more than `RETENTION_DAYS` (default is 4) ago +``` + +### Local volumes cleaner + +**Purpose:** Deletes local volumes when node disk space is close to the threshold + +**How it runs:** Runs as `dind-lv-monitor` DaemonSet. Installed in case the Runner uses local volumes `.Values.storage.backend == local` + +**Triggered by:** Disk space usage or inode usage that exceeds thresholds (configurable) + +**Configuration:** + +Override environment variables for `dind-lv-monitor` daemonset: + +```yaml +volumeProvisioner: + dind-lv-monitor: + env: + KB_USAGE_THRESHOLD: 60 # default 80 (percentage) + INODE_USAGE_THRESHOLD: 60 # default 80 +``` + +### Rootless DinD + +DinD pod runs a `priviliged` container with **rootfull** docker. +To run the docker daemon as non-root user (**rootless** mode), change dind image tag: + +`values.yaml` +```yaml +runtime: + dind: + image: + tag: rootless +``` + +### ARM + +With the Codefresh Runner, you can run native ARM64v8 builds. + +> **Note!** +> You cannot run both amd64 and arm64 images within the same pipeline. As one pipeline can map only to one runtime, you can run either amd64 or arm64 within the same pipeline. + +Provide `nodeSelector` and(or) `tolerations` for dind pods: + +`values.yaml` +```yaml +runtime: + dind: + nodeSelector: + arch: arm64 + tolerations: + - key: arch + operator: Equal + value: arm64 + effect: NoSchedule +``` + +### Openshift + +To install Codefresh Runner on OpenShift use the following `values.yaml` example + +```yaml +runner: + podSecurityContext: + enabled: false + +volumeProvisioner: + podSecurityContext: + enabled: false + env: + PRIVILEGED_CONTAINER: true + dind-lv-monitor: + containerSecurityContext: + enabled: true + privileged: true + volumePermissions: + enabled: true + securityContext: + privileged: true + runAsUser: auto +``` + +Grant `privileged` SCC to `cf-runtime-runner` and `cf-runtime-volume-provisioner` service accounts. + +```console +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-runner + +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-volume-provisioner +``` + +### On-premise + +If you have [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) deployed, you can install Codefresh Runner in **agentless** mode. + +**What is agentless mode?** + +Agent (aka venona) is Runner component which responsible for calling Codefresh API to run builds and create dind/engine pods and pvc objects. Agent can only be assigned to a single account, thus you can't share one runtime across multiple accounts. However, with **agentless** mode it's possible to register the runtime as **system**-type runtime so it's registered on the platform level and can be assigned/shared across multiple accounts. + +**What are the prerequisites?** +- You have a running [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) control-plane environment +- You have a Codefresh API token with platform **Admin** permissions scope + +### How to deploy agentless runtime when it's on the SAME k8s cluster as On-Premises control-plane environment? + +- Enable cluster-level permissions for cf-api (On-Premises control-plane component) + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) Helm chart +```yaml +cfapi: + ... + # -- Enable ClusterRole/ClusterRoleBinding + rbac: + namespaced: false +``` + +- Set the following values for Runner Helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=true` + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + runtimeName: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: true + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to check the runtime. Assign it to the required account(s). Run test pipeline on it. + +### How to deploy agentless runtime when it's on the DIFFERENT k8s cluster than On-Premises control-plane environment? + +In this case, it's required to mount runtime cluster's `KUBECONFIG` into On-Premises `cf-api` deployment + +- Create the neccessary RBAC resources + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +extraResources: +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: codefresh-role + namespace: '{{ .Release.Namespace }}' + rules: + - apiGroups: [""] + resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshots"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: codefresh-role + subjects: + - kind: ServiceAccount + name: codefresh-runtime-user + namespace: '{{ .Release.Namespace }}' +- apiVersion: v1 + kind: Secret + metadata: + name: codefresh-runtime-user-token + namespace: '{{ .Release.Namespace }}' + annotations: + kubernetes.io/service-account.name: codefresh-runtime-user + type: kubernetes.io/service-account-token +``` + +- Set up the following environment variables to create a `KUBECONFIG` file + +```shell +NAMESPACE=cf-runtime +CLUSTER_NAME=prod-ue1-some-cluster-name +CURRENT_CONTEXT=$(kubectl config current-context) + +USER_TOKEN_VALUE=$(kubectl -n cf-runtime get secret/codefresh-runtime-user-token -o=go-template='{{.data.token}}' | base64 --decode) +CURRENT_CLUSTER=$(kubectl config view --raw -o=go-template='{{range .contexts}}{{if eq .name "'''${CURRENT_CONTEXT}'''"}}{{ index .context "cluster" }}{{end}}{{end}}') +CLUSTER_CA=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}"{{with index .cluster "certificate-authority-data" }}{{.}}{{end}}"{{ end }}{{ end }}') +CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}{{ .cluster.server }}{{end}}{{ end }}') + +export -p USER_TOKEN_VALUE CURRENT_CONTEXT CURRENT_CLUSTER CLUSTER_CA CLUSTER_SERVER CLUSTER_NAME +``` + +- Create a kubeconfig file + +```console +cat << EOF > $CLUSTER_NAME-kubeconfig +apiVersion: v1 +kind: Config +current-context: ${CLUSTER_NAME} +contexts: +- name: ${CLUSTER_NAME} + context: + cluster: ${CLUSTER_NAME} + user: codefresh-runtime-user + namespace: ${NAMESPACE} +clusters: +- name: ${CLUSTER_NAME} + cluster: + certificate-authority-data: ${CLUSTER_CA} + server: ${CLUSTER_SERVER} +users: +- name: ${CLUSTER_NAME} + user: + token: ${USER_TOKEN_VALUE} +EOF +``` + +- **Switch context to On-Premises control-plane cluster**. Create k8s secret (via any tool like [ESO](https://external-secrets.io/v0.4.4/), `kubectl`, etc ) containing runtime cluster's `KUBECONFG` created in previous step. + +```shell +NAMESPACE=codefresh +kubectl create secret generic dind-runtime-clusters --from-file=$CLUSTER_NAME=$CLUSTER_NAME-kubeconfig -n $NAMESPACE +``` + +- Mount secret containing runtime cluster's `KUBECONFG` into cf-api in On-Premises control-plane cluster + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) helm chart +```yaml +cf-api: + ... + volumes: + dind-clusters: + enabled: true + type: secret + nameOverride: dind-runtime-clusters + optional: true +``` +> volumeMount `/etc/kubeconfig` is already configured in cf-api Helm chart template. No need to specify it. + +- Set the following values for Runner helm chart + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=false` + +**Important!** +`.Values.global.name` ("system/" prefix is ignored!) should match the cluster name (key in `dind-runtime-clusters` secret created previously) +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + name: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: false + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- (optional) Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to see the runtime. Assign it to the required account(s). + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| oci://quay.io/codefresh/charts | cf-common | 0.16.0 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| appProxy.affinity | object | `{}` | Set affinity | +| appProxy.enabled | bool | `false` | Enable app-proxy | +| appProxy.env | object | `{}` | Add additional env vars | +| appProxy.image | object | `{"registry":"quay.io","repository":"codefresh/cf-app-proxy","tag":"0.0.47"}` | Set image | +| appProxy.ingress.annotations | object | `{}` | Set extra annotations for ingress object | +| appProxy.ingress.class | string | `""` | Set ingress class | +| appProxy.ingress.host | string | `""` | Set DNS hostname the ingress will use | +| appProxy.ingress.pathPrefix | string | `""` | Set path prefix for ingress (keep empty for default `/` path) | +| appProxy.ingress.tlsSecret | string | `""` | Set k8s tls secret for the ingress object | +| appProxy.nodeSelector | object | `{}` | Set node selector | +| appProxy.podAnnotations | object | `{}` | Set pod annotations | +| appProxy.podSecurityContext | object | `{}` | Set security context for the pod | +| appProxy.rbac | object | `{"create":true,"namespaced":true,"rules":[]}` | RBAC parameters | +| appProxy.rbac.create | bool | `true` | Create RBAC resources | +| appProxy.rbac.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| appProxy.rbac.rules | list | `[]` | Add custom rule to the role | +| appProxy.readinessProbe | object | See below | Readiness probe configuration | +| appProxy.replicasCount | int | `1` | Set number of pods | +| appProxy.resources | object | `{}` | Set requests and limits | +| appProxy.serviceAccount | object | `{"annotations":{},"create":true,"name":"","namespaced":true}` | Service Account parameters | +| appProxy.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| appProxy.serviceAccount.create | bool | `true` | Create service account | +| appProxy.serviceAccount.name | string | `""` | Override service account name | +| appProxy.serviceAccount.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| appProxy.tolerations | list | `[]` | Set tolerations | +| appProxy.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| dockerRegistry | string | `""` | | +| event-exporter | object | See below | Event exporter parameters | +| event-exporter.affinity | object | `{}` | Set affinity | +| event-exporter.enabled | bool | `false` | Enable event-exporter | +| event-exporter.env | object | `{}` | Add additional env vars | +| event-exporter.image | object | `{"registry":"docker.io","repository":"codefresh/k8s-event-exporter","tag":"latest"}` | Set image | +| event-exporter.nodeSelector | object | `{}` | Set node selector | +| event-exporter.podAnnotations | object | `{}` | Set pod annotations | +| event-exporter.podSecurityContext | object | See below | Set security context for the pod | +| event-exporter.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| event-exporter.rbac.create | bool | `true` | Create RBAC resources | +| event-exporter.rbac.rules | list | `[]` | Add custom rule to the role | +| event-exporter.replicasCount | int | `1` | Set number of pods | +| event-exporter.resources | object | `{}` | Set resources | +| event-exporter.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| event-exporter.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| event-exporter.serviceAccount.create | bool | `true` | Create service account | +| event-exporter.serviceAccount.name | string | `""` | Override service account name | +| event-exporter.tolerations | list | `[]` | Set tolerations | +| event-exporter.updateStrategy | object | `{"type":"Recreate"}` | Upgrade strategy | +| extraResources | list | `[]` | Array of extra objects to deploy with the release | +| fullnameOverride | string | `""` | String to fully override cf-runtime.fullname template | +| global | object | See below | Global parameters | +| global.accountId | string | `""` | Account ID (required!) Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information | +| global.agentName | string | `""` | Agent Name (optional!) If omitted, the following format will be used `{{ .Values.global.context }}_{{ .Release.Namespace }}` | +| global.agentToken | string | `""` | DEPRECATED Agent token in plain text. !!! MUST BE provided if migrating from < 6.x chart version | +| global.agentTokenSecretKeyRef | object | `{}` | DEPRECATED Agent token that references an existing secret containing API key. !!! MUST BE provided if migrating from < 6.x chart version | +| global.codefreshHost | string | `"https://g.codefresh.io"` | URL of Codefresh Platform (required!) | +| global.codefreshToken | string | `""` | User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) Ref: https://g.codefresh.io/user/settings (see API Keys) Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) | +| global.codefreshTokenSecretKeyRef | object | `{}` | User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) | +| global.context | string | `""` | K8s context name (required!) | +| global.imagePullSecrets | list | `[]` | Global Docker registry secret names as array | +| global.imageRegistry | string | `""` | Global Docker image registry | +| global.runtimeName | string | `""` | Runtime name (optional!) If omitted, the following format will be used `{{ .Values.global.context }}/{{ .Release.Namespace }}` | +| monitor.affinity | object | `{}` | Set affinity | +| monitor.enabled | bool | `false` | Enable monitor Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#install-monitoring-component | +| monitor.env | object | `{}` | Add additional env vars | +| monitor.image | object | `{"registry":"quay.io","repository":"codefresh/cf-k8s-agent","tag":"1.3.17"}` | Set image | +| monitor.nodeSelector | object | `{}` | Set node selector | +| monitor.podAnnotations | object | `{}` | Set pod annotations | +| monitor.podSecurityContext | object | `{}` | | +| monitor.rbac | object | `{"create":true,"namespaced":true,"rules":[]}` | RBAC parameters | +| monitor.rbac.create | bool | `true` | Create RBAC resources | +| monitor.rbac.namespaced | bool | `true` | Use Role(true)/ClusterRole(true) | +| monitor.rbac.rules | list | `[]` | Add custom rule to the role | +| monitor.readinessProbe | object | See below | Readiness probe configuration | +| monitor.replicasCount | int | `1` | Set number of pods | +| monitor.resources | object | `{}` | Set resources | +| monitor.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| monitor.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| monitor.serviceAccount.create | bool | `true` | Create service account | +| monitor.serviceAccount.name | string | `""` | Override service account name | +| monitor.tolerations | list | `[]` | Set tolerations | +| monitor.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| nameOverride | string | `""` | String to partially override cf-runtime.fullname template (will maintain the release name) | +| podMonitor | object | See below | Add podMonitor (for engine pods) | +| podMonitor.main.enabled | bool | `false` | Enable pod monitor for engine pods | +| podMonitor.runner.enabled | bool | `false` | Enable pod monitor for runner pod | +| podMonitor.volume-provisioner.enabled | bool | `false` | Enable pod monitor for volumeProvisioner pod | +| re | object | `{}` | | +| runner | object | See below | Runner parameters | +| runner.affinity | object | `{}` | Set affinity | +| runner.enabled | bool | `true` | Enable the runner | +| runner.env | object | `{}` | Add additional env vars | +| runner.image | object | `{"registry":"quay.io","repository":"codefresh/venona","tag":"1.10.2"}` | Set image | +| runner.init | object | `{"image":{"registry":"quay.io","repository":"codefresh/cli","tag":"0.85.0-rootless"},"resources":{"limits":{"cpu":"1","memory":"512Mi"},"requests":{"cpu":"0.2","memory":"256Mi"}}}` | Init container | +| runner.nodeSelector | object | `{}` | Set node selector | +| runner.podAnnotations | object | `{}` | Set pod annotations | +| runner.podSecurityContext | object | See below | Set security context for the pod | +| runner.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| runner.rbac.create | bool | `true` | Create RBAC resources | +| runner.rbac.rules | list | `[]` | Add custom rule to the role | +| runner.readinessProbe | object | See below | Readiness probe configuration | +| runner.replicasCount | int | `1` | Set number of pods | +| runner.resources | object | `{}` | Set requests and limits | +| runner.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| runner.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| runner.serviceAccount.create | bool | `true` | Create service account | +| runner.serviceAccount.name | string | `""` | Override service account name | +| runner.sidecar | object | `{"enabled":false,"env":{"RECONCILE_INTERVAL":300},"image":{"registry":"quay.io","repository":"codefresh/codefresh-shell","tag":"0.0.2"},"resources":{}}` | Sidecar container Reconciles runtime spec from Codefresh API for drift detection | +| runner.tolerations | list | `[]` | Set tolerations | +| runner.updateStrategy | object | `{"type":"RollingUpdate"}` | Upgrade strategy | +| runtime | object | See below | Set runtime parameters | +| runtime.accounts | list | `[]` | (for On-Premise only) Assign accounts to runtime (list of account ids) | +| runtime.agent | bool | `true` | (for On-Premise only) Enable agent | +| runtime.description | string | `""` | Runtime description | +| runtime.dind | object | `{"affinity":{},"env":{"DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE":true},"image":{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/dind","tag":"26.1.4-1.28.7"},"nodeSelector":{},"podAnnotations":{},"podLabels":{},"pvcs":{"dind":{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}},"resources":{"limits":{"cpu":"400m","memory":"800Mi"},"requests":null},"schedulerName":"","serviceAccount":"codefresh-engine","tolerations":[],"userAccess":true,"userVolumeMounts":{},"userVolumes":{}}` | Parameters for DinD (docker-in-docker) pod (aka "runtime" pod). | +| runtime.dind.affinity | object | `{}` | Set affinity | +| runtime.dind.env | object | `{"DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE":true}` | Set additional env vars. | +| runtime.dind.image | object | `{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/dind","tag":"26.1.4-1.28.7"}` | Set dind image. | +| runtime.dind.nodeSelector | object | `{}` | Set node selector. | +| runtime.dind.podAnnotations | object | `{}` | Set pod annotations. | +| runtime.dind.podLabels | object | `{}` | Set pod labels. | +| runtime.dind.pvcs | object | `{"dind":{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}}` | PV claim spec parametes. | +| runtime.dind.pvcs.dind | object | `{"annotations":{},"name":"dind","reuseVolumeSelector":"codefresh-app,io.codefresh.accountName","reuseVolumeSortOrder":"pipeline_id","storageClassName":"{{ include \"dind-volume-provisioner.storageClassName\" . }}","volumeSize":"16Gi"}` | Default dind PVC parameters | +| runtime.dind.pvcs.dind.annotations | object | `{}` | PV annotations. | +| runtime.dind.pvcs.dind.name | string | `"dind"` | PVC name prefix. Keep `dind` as default! Don't change! | +| runtime.dind.pvcs.dind.reuseVolumeSelector | string | `"codefresh-app,io.codefresh.accountName"` | PV reuse selector. Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#volume-reuse-policy | +| runtime.dind.pvcs.dind.storageClassName | string | `"{{ include \"dind-volume-provisioner.storageClassName\" . }}"` | PVC storage class name. Change ONLY if you need to use storage class NOT from Codefresh volume-provisioner | +| runtime.dind.pvcs.dind.volumeSize | string | `"16Gi"` | PVC size. | +| runtime.dind.resources | object | `{"limits":{"cpu":"400m","memory":"800Mi"},"requests":null}` | Set dind resources. | +| runtime.dind.schedulerName | string | `""` | Set scheduler name. | +| runtime.dind.serviceAccount | string | `"codefresh-engine"` | Set service account for pod. | +| runtime.dind.tolerations | list | `[]` | Set tolerations. | +| runtime.dind.userAccess | bool | `true` | Keep `true` as default! | +| runtime.dind.userVolumeMounts | object | `{}` | Add extra volume mounts | +| runtime.dind.userVolumes | object | `{}` | Add extra volumes | +| runtime.dindDaemon | object | See below | DinD pod daemon config | +| runtime.engine | object | `{"affinity":{},"command":["npm","run","start"],"env":{"CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS":1000,"DOCKER_REQUEST_TIMEOUT_MS":30000,"FORCE_COMPOSE_SERIAL_PULL":false,"LOGGER_LEVEL":"debug","LOG_OUTGOING_HTTP_REQUESTS":false,"METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS":false,"METRICS_PROMETHEUS_ENABLED":true,"METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS":false,"METRICS_PROMETHEUS_HOST":"0.0.0.0","METRICS_PROMETHEUS_PORT":9100},"image":{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/engine","tag":"1.173.6"},"nodeSelector":{},"podAnnotations":{},"podLabels":{},"resources":{"limits":{"cpu":"1000m","memory":"2048Mi"},"requests":{"cpu":"100m","memory":"128Mi"}},"runtimeImages":{"COMPOSE_IMAGE":"quay.io/codefresh/compose:v2.28.1-1.5.0","CONTAINER_LOGGER_IMAGE":"quay.io/codefresh/cf-container-logger:1.11.6","CR_6177_FIXER":"quay.io/codefresh/alpine:edge","DOCKER_BUILDER_IMAGE":"quay.io/codefresh/cf-docker-builder:1.3.13","DOCKER_PULLER_IMAGE":"quay.io/codefresh/cf-docker-puller:8.0.17","DOCKER_PUSHER_IMAGE":"quay.io/codefresh/cf-docker-pusher:6.0.15","DOCKER_TAG_PUSHER_IMAGE":"quay.io/codefresh/cf-docker-tag-pusher:1.3.14","FS_OPS_IMAGE":"quay.io/codefresh/fs-ops:1.2.3","GC_BUILDER_IMAGE":"quay.io/codefresh/cf-gc-builder:0.5.3","GIT_CLONE_IMAGE":"quay.io/codefresh/cf-git-cloner:10.1.26","KUBE_DEPLOY":"quay.io/codefresh/cf-deploy-kubernetes:16.1.11","PIPELINE_DEBUGGER_IMAGE":"quay.io/codefresh/cf-debugger:1.3.0","TEMPLATE_ENGINE":"quay.io/codefresh/pikolo:0.14.1"},"schedulerName":"","serviceAccount":"codefresh-engine","tolerations":[],"userEnvVars":[],"workflowLimits":{"MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS":600,"MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION":86400,"MAXIMUM_ELECTED_STATE_AGE_ALLOWED":900,"MAXIMUM_RETRY_ATTEMPTS_ALLOWED":20,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED":900,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE":300,"TIME_ENGINE_INACTIVE_UNTIL_TERMINATION":300,"TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY":60,"TIME_INACTIVE_UNTIL_TERMINATION":2700}}` | Parameters for Engine pod (aka "pipeline" orchestrator). | +| runtime.engine.affinity | object | `{}` | Set affinity | +| runtime.engine.command | list | `["npm","run","start"]` | Set container command. | +| runtime.engine.env | object | `{"CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS":1000,"DOCKER_REQUEST_TIMEOUT_MS":30000,"FORCE_COMPOSE_SERIAL_PULL":false,"LOGGER_LEVEL":"debug","LOG_OUTGOING_HTTP_REQUESTS":false,"METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS":false,"METRICS_PROMETHEUS_ENABLED":true,"METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS":false,"METRICS_PROMETHEUS_HOST":"0.0.0.0","METRICS_PROMETHEUS_PORT":9100}` | Set additional env vars. | +| runtime.engine.env.CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS | int | `1000` | Interval to check the exec status in the container-logger | +| runtime.engine.env.DOCKER_REQUEST_TIMEOUT_MS | int | `30000` | Timeout while doing requests to the Docker daemon | +| runtime.engine.env.FORCE_COMPOSE_SERIAL_PULL | bool | `false` | If "true", composition images will be pulled sequentially | +| runtime.engine.env.LOGGER_LEVEL | string | `"debug"` | Level of logging for engine | +| runtime.engine.env.LOG_OUTGOING_HTTP_REQUESTS | bool | `false` | Enable debug-level logging of outgoing HTTP/HTTPS requests | +| runtime.engine.env.METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS | bool | `false` | Enable collecting process metrics | +| runtime.engine.env.METRICS_PROMETHEUS_ENABLED | bool | `true` | Enable emitting metrics from engine | +| runtime.engine.env.METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS | bool | `false` | Enable legacy metrics | +| runtime.engine.env.METRICS_PROMETHEUS_HOST | string | `"0.0.0.0"` | Host for Prometheus metrics server | +| runtime.engine.env.METRICS_PROMETHEUS_PORT | int | `9100` | Port for Prometheus metrics server | +| runtime.engine.image | object | `{"pullPolicy":"IfNotPresent","registry":"quay.io","repository":"codefresh/engine","tag":"1.173.6"}` | Set image. | +| runtime.engine.nodeSelector | object | `{}` | Set node selector. | +| runtime.engine.podAnnotations | object | `{}` | Set pod annotations. | +| runtime.engine.podLabels | object | `{}` | Set pod labels. | +| runtime.engine.resources | object | `{"limits":{"cpu":"1000m","memory":"2048Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}` | Set resources. | +| runtime.engine.runtimeImages | object | See below. | Set system(base) runtime images. | +| runtime.engine.schedulerName | string | `""` | Set scheduler name. | +| runtime.engine.serviceAccount | string | `"codefresh-engine"` | Set service account for pod. | +| runtime.engine.tolerations | list | `[]` | Set tolerations. | +| runtime.engine.userEnvVars | list | `[]` | Set extra env vars | +| runtime.engine.workflowLimits | object | `{"MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS":600,"MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION":86400,"MAXIMUM_ELECTED_STATE_AGE_ALLOWED":900,"MAXIMUM_RETRY_ATTEMPTS_ALLOWED":20,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED":900,"MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE":300,"TIME_ENGINE_INACTIVE_UNTIL_TERMINATION":300,"TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY":60,"TIME_INACTIVE_UNTIL_TERMINATION":2700}` | Set workflow limits. | +| runtime.engine.workflowLimits.MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS | int | `600` | Maximum time allowed to the engine to wait for the pre-steps (aka "Initializing Process") to succeed; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION | int | `86400` | Maximum time for workflow execution; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_ELECTED_STATE_AGE_ALLOWED | int | `900` | Maximum time allowed to workflow to spend in "elected" state; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_RETRY_ATTEMPTS_ALLOWED | int | `20` | Maximum retry attempts allowed for workflow. | +| runtime.engine.workflowLimits.MAXIMUM_TERMINATING_STATE_AGE_ALLOWED | int | `900` | Maximum time allowed to workflow to spend in "terminating" state until force terminated; seconds. | +| runtime.engine.workflowLimits.MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE | int | `300` | Maximum time allowed to workflow to spend in "terminating" state without logs activity until force terminated; seconds. | +| runtime.engine.workflowLimits.TIME_ENGINE_INACTIVE_UNTIL_TERMINATION | int | `300` | Time since the last health check report after which workflow is terminated; seconds. | +| runtime.engine.workflowLimits.TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY | int | `60` | Time since the last health check report after which the engine is considered unhealthy; seconds. | +| runtime.engine.workflowLimits.TIME_INACTIVE_UNTIL_TERMINATION | int | `2700` | Time since the last workflow logs activity after which workflow is terminated; seconds. | +| runtime.gencerts | object | See below | Parameters for `gencerts-dind` post-upgrade/install hook | +| runtime.inCluster | bool | `true` | (for On-Premise only) Set inCluster runtime | +| runtime.patch | object | See below | Parameters for `runtime-patch` post-upgrade/install hook | +| runtime.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| runtime.rbac.create | bool | `true` | Create RBAC resources | +| runtime.rbac.rules | list | `[]` | Add custom rule to the engine role | +| runtime.runtimeExtends | list | `["system/default/hybrid/k8s_low_limits"]` | Set parent runtime to inherit. Should not be changes. Parent runtime is controlled from Codefresh side. | +| runtime.serviceAccount | object | `{"annotations":{},"create":true}` | Set annotation on engine Service Account Ref: https://codefresh.io/docs/docs/administration/codefresh-runner/#injecting-aws-arn-roles-into-the-cluster | +| serviceMonitor | object | See below | Add serviceMonitor | +| serviceMonitor.main.enabled | bool | `false` | Enable service monitor for dind pods | +| storage.azuredisk.cachingMode | string | `"None"` | | +| storage.azuredisk.skuName | string | `"Premium_LRS"` | Set storage type (`Premium_LRS`) | +| storage.backend | string | `"local"` | Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) | +| storage.ebs.accessKeyId | string | `""` | Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions | +| storage.ebs.accessKeyIdSecretKeyRef | object | `{}` | Existing secret containing AWS_ACCESS_KEY_ID. | +| storage.ebs.availabilityZone | string | `"us-east-1a"` | Set EBS volumes availability zone (required) | +| storage.ebs.encrypted | string | `"false"` | Enable encryption (optional) | +| storage.ebs.kmsKeyId | string | `""` | Set KMS encryption key ID (optional) | +| storage.ebs.secretAccessKey | string | `""` | Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions | +| storage.ebs.secretAccessKeySecretKeyRef | object | `{}` | Existing secret containing AWS_SECRET_ACCESS_KEY | +| storage.ebs.volumeType | string | `"gp2"` | Set EBS volume type (`gp2`/`gp3`/`io1`) (required) | +| storage.fsType | string | `"ext4"` | Set filesystem type (`ext4`/`xfs`) | +| storage.gcedisk.availabilityZone | string | `"us-west1-a"` | Set GCP volume availability zone | +| storage.gcedisk.serviceAccountJson | string | `""` | Set Google SA JSON key for volume-provisioner (optional) | +| storage.gcedisk.serviceAccountJsonSecretKeyRef | object | `{}` | Existing secret containing containing Google SA JSON key for volume-provisioner (optional) | +| storage.gcedisk.volumeType | string | `"pd-ssd"` | Set GCP volume backend type (`pd-ssd`/`pd-standard`) | +| storage.local.volumeParentDir | string | `"/var/lib/codefresh/dind-volumes"` | Set volume path on the host filesystem | +| storage.mountAzureJson | bool | `false` | | +| volumeProvisioner | object | See below | Volume Provisioner parameters | +| volumeProvisioner.affinity | object | `{}` | Set affinity | +| volumeProvisioner.dind-lv-monitor | object | See below | `dind-lv-monitor` DaemonSet parameters (local volumes cleaner) | +| volumeProvisioner.enabled | bool | `true` | Enable volume-provisioner | +| volumeProvisioner.env | object | `{}` | Add additional env vars | +| volumeProvisioner.image | object | `{"registry":"quay.io","repository":"codefresh/dind-volume-provisioner","tag":"1.35.0"}` | Set image | +| volumeProvisioner.nodeSelector | object | `{}` | Set node selector | +| volumeProvisioner.podAnnotations | object | `{}` | Set pod annotations | +| volumeProvisioner.podSecurityContext | object | See below | Set security context for the pod | +| volumeProvisioner.rbac | object | `{"create":true,"rules":[]}` | RBAC parameters | +| volumeProvisioner.rbac.create | bool | `true` | Create RBAC resources | +| volumeProvisioner.rbac.rules | list | `[]` | Add custom rule to the role | +| volumeProvisioner.replicasCount | int | `1` | Set number of pods | +| volumeProvisioner.resources | object | `{}` | Set resources | +| volumeProvisioner.serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | Service Account parameters | +| volumeProvisioner.serviceAccount.annotations | object | `{}` | Additional service account annotations | +| volumeProvisioner.serviceAccount.create | bool | `true` | Create service account | +| volumeProvisioner.serviceAccount.name | string | `""` | Override service account name | +| volumeProvisioner.tolerations | list | `[]` | Set tolerations | +| volumeProvisioner.updateStrategy | object | `{"type":"Recreate"}` | Upgrade strategy | + diff --git a/charts/codefresh/cf-runtime/6.3.52/README.md.gotmpl b/charts/codefresh/cf-runtime/6.3.52/README.md.gotmpl new file mode 100644 index 000000000..96e5ca574 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/README.md.gotmpl @@ -0,0 +1,1007 @@ +## Codefresh Runner + +{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }} + +Helm chart for deploying [Codefresh Runner](https://codefresh.io/docs/docs/installation/codefresh-runner/) to Kubernetes. + +## Table of Content + +- [Prerequisites](#prerequisites) +- [Get Chart Info](#get-chart-info) +- [Install Chart](#install-chart) +- [Chart Configuration](#chart-configuration) +- [Upgrade Chart](#upgrade-chart) + - [To 2.x](#to-2-x) + - [To 3.x](#to-3-x) + - [To 4.x](#to-4-x) + - [To 5.x](#to-5-x) + - [To 6.x](#to-6-x) +- [Architecture](#architecture) +- [Configuration](#configuration) + - [EBS backend volume configuration in AWS](#ebs-backend-volume-configuration) + - [Azure Disks backend volume configuration in AKS](#azure-disks-backend-volume-configuration) + - [GCE Disks backend volume configuration in GKE](#gce-disks-backend-volume-configuration-in-gke) + - [Custom volume mounts](#custom-volume-mounts) + - [Custom global environment variables](#custom-global-environment-variables) + - [Volume reuse policy](#volume-reuse-policy) + - [Volume cleaners](#volume-cleaners) + - [Rootless DinD](#rootless-dind) + - [ARM](#arm) + - [Openshift](#openshift) + - [On-premise](#on-premise) + +## Prerequisites + +- Kubernetes **1.19+** +- Helm **3.8.0+** + +⚠️⚠️⚠️ +> Since version 6.2.x chart is pushed **only** to OCI registry at `oci://quay.io/codefresh/cf-runtime` + +> Versions prior to 6.2.x are still available in ChartMuseum at `http://chartmuseum.codefresh.io/cf-runtime` + +## Get Chart Info + +```console +helm show all oci://quay.io/codefresh/cf-runtime +``` +See [Use OCI-based registries](https://helm.sh/docs/topics/registries/) + +## Install Chart + +**Important:** only helm3 is supported + +- Specify the following mandatory values + +`values.yaml` +```yaml +# -- Global parameters +# @default -- See below +global: + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used '{{ `{{ .Values.global.context }}_{{ .Release.Namespace }}` }}' + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used '{{ `{{ .Values.global.context }}/{{ .Release.Namespace }}` }}' + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace +``` + +- Install chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace codefresh +``` + +## Chart Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +## Upgrade Chart + +### To 2.x + +This major release renames and deprecated several values in the chart. Most of the workload templates have been refactored. + +Affected values: +- `dockerRegistry` is deprecated. Replaced with `global.imageRegistry` +- `re` is renamed to `runtime` +- `storage.localVolumeMonitor` is replaced with `volumeProvisioner.dind-lv-monitor` +- `volumeProvisioner.volume-cleanup` is replaced with `volumeProvisioner.dind-volume-cleanup` +- `image` values structure has been updated. Split to `image.registry` `image.repository` `image.tag` +- pod's `annotations` is renamed to `podAnnotations` + +### To 3.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release adds [runtime-environment](https://codefresh.io/docs/docs/installation/codefresh-runner/#runtime-environment-specification) spec into chart templates. +That means it is possible to set parametes for `dind` and `engine` pods via [values.yaml](./values.yaml). + +**If you had any overrides (i.e. tolerations/nodeSelector/environment variables/etc) added in runtime spec via [codefresh CLI](https://codefresh-io.github.io/cli/) (for example, you did use [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands to modify the runtime-environment), you MUST add these into chart's [values.yaml](./values.yaml) for `.Values.runtime.dind` or(and) .`Values.runtime.engine`** + +**For backward compatibility, you can disable updating runtime-environment spec via** `.Values.runtime.patch.enabled=false` + +Affected values: +- added **mandatory** `global.codefreshToken`/`global.codefreshTokenSecretKeyRef` **You must specify it before the upgrade!** +- `runtime.engine` is added +- `runtime.dind` is added +- `global.existingAgentToken` is replaced with `global.agentTokenSecretKeyRef` +- `global.existingDindCertsSecret` is replaced with `global.dindCertsSecretRef` + +### To 4.x + +This major release adds **agentless inCluster** runtime mode (relevant only for [Codefresh On-Premises](#on-premise) users) + +Affected values: +- `runtime.agent` / `runtime.inCluster` / `runtime.accounts` / `runtime.description` are added + +### To 5.x + +This major release converts `.runtime.dind.pvcs` from **list** to **dict** + +> 4.x chart's values example: +```yaml +runtime: + dind: + pvcs: + - name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +> 5.x chart's values example: +```yaml +runtime: + dind: + pvcs: + dind: + name: dind + storageClassName: my-storage-class-name + volumeSize: 32Gi + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +Affected values: +- `.runtime.dind.pvcs` converted from **list** to **dict** + +### To 6.x + +⚠️⚠️⚠️ +### READ this before the upgrade! + +This major release deprecates previously required `codefresh runner init --generate-helm-values-file`. + +Affected values: +- **Replaced** `.monitor.clusterId` with `.global.context` as **mandatory** value! +- **Deprecated** `.global.agentToken` / `.global.agentTokenSecretKeyRef` +- **Removed** `.global.agentId` +- **Removed** `.global.keys` / `.global.dindCertsSecretRef` +- **Removed** `.global.existingAgentToken` / `existingDindCertsSecret` +- **Removed** `.monitor.clusterId` / `.monitor.token` / `.monitor.existingMonitorToken` + +#### Migrate the Helm chart from version 5.x to 6.x + +Given this is the legacy `generated_values.yaml` values: + +> legacy `generated_values.yaml` +```yaml +{ + "appProxy": { + "enabled": false, + }, + "monitor": { + "enabled": false, + "clusterId": "my-cluster-name", + "token": "1234567890" + }, + "global": { + "namespace": "namespace", + "codefreshHost": "https://g.codefresh.io", + "agentToken": "0987654321", + "agentId": "agent-id-here", + "agentName": "my-cluster-name_my-namespace", + "accountId": "my-account-id", + "runtimeName": "my-cluster-name/my-namespace", + "codefreshToken": "1234567890", + "keys": { + "key": "-----BEGIN RSA PRIVATE KEY-----...", + "csr": "-----BEGIN CERTIFICATE REQUEST-----...", + "ca": "-----BEGIN CERTIFICATE-----...", + "serverCert": "-----BEGIN CERTIFICATE-----..." + } + } +} +``` + +Update `values.yaml` for new chart version: + +> For existing installation for backward compatibility `.Values.global.agentToken/agentTokenSecretKeyRef` **must be provided!** For installation from scratch this value is no longer required. + +> updated `values.yaml` +```yaml +global: + codefreshToken: "1234567890" + accountId: "my-account-id" + context: "my-cluster-name" + agentToken: "0987654321" # MANDATORY when migrating from < 6.x chart version ! + agentName: "my-cluster-name_my-namespace" # optional + runtimeName: "my-cluster-name/my-namespace" # optional +``` + +> **Note!** Though it's still possible to update runtime-environment via [get](https://codefresh-io.github.io/cli/runtime-environments/get-runtime-environments/) and [patch](https://codefresh-io.github.io/cli/runtime-environments/apply-runtime-environments/) commands, it's recommended to enable sidecar container to pull runtime spec from Codefresh API to detect any drift in configuration. + +```yaml +runner: + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: true +``` + +## Architecture + +[Codefresh Runner architecture](https://codefresh.io/docs/docs/installation/codefresh-runner/#codefresh-runner-architecture) + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). + +### EBS backend volume configuration + +`dind-volume-provisioner` should have permissions to create/attach/detach/delete/get EBS volumes + +Minimal IAM policy for `dind-volume-provisioner` + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "ec2:AttachVolume", + "ec2:CreateSnapshot", + "ec2:CreateTags", + "ec2:CreateVolume", + "ec2:DeleteSnapshot", + "ec2:DeleteTags", + "ec2:DeleteVolume", + "ec2:DescribeInstances", + "ec2:DescribeSnapshots", + "ec2:DescribeTags", + "ec2:DescribeVolumes", + "ec2:DetachVolume" + ], + "Resource": "*" + } + ] +} +``` + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM role + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] +``` + +2. Pass static credentials in `.Values.storage.ebs.accessKeyId/accessKeyIdSecretKeyRef` and `.Values.storage.ebs.secretAccessKey/secretAccessKeySecretKeyRef` + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: ebs-csi + + ebs: + availabilityZone: "us-east-1a" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" +``` + +### Custom volume mounts + +You can add your own volumes and volume mounts in the runtime environment, so that all pipeline steps will have access to the same set of external files. + +```yaml +runtime: + dind: + userVolumes: + regctl-docker-registry: + name: regctl-docker-registry + secret: + items: + - key: .dockerconfigjson + path: config.json + secretName: regctl-docker-registry + optional: true + userVolumeMounts: + regctl-docker-registry: + name: regctl-docker-registry + mountPath: /home/appuser/.docker/ + readOnly: true + +``` + +### Azure Disks backend volume configuration + +`dind-volume-provisioner` should have permissions to create/delete/get Azure Disks + +Role definition for `dind-volume-provisioner` + +`dind-volume-provisioner-role.json` +```json +{ + "Name": "CodefreshDindVolumeProvisioner", + "Description": "Perform create/delete/get disks", + "IsCustom": true, + "Actions": [ + "Microsoft.Compute/disks/read", + "Microsoft.Compute/disks/write", + "Microsoft.Compute/disks/delete" + + ], + "AssignableScopes": ["/subscriptions/"] +} +``` + +When creating an AKS cluster in Azure there is the option to use a [managed identity](https://learn.microsoft.com/en-us/azure/aks/use-managed-identity) that is assigned to the kubelet. This identity is assigned to the underlying node pool in the AKS cluster and can then be used by the dind-volume-provisioner. + +```console +export ROLE_DEFINITIN_FILE=dind-volume-provisioner-role.json +export SUBSCRIPTION_ID=$(az account show --query "id" | xargs echo ) +export RESOURCE_GROUP= +export AKS_NAME= +export LOCATION=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query location | xargs echo) +export NODES_RESOURCE_GROUP=MC_${RESOURCE_GROUP}_${AKS_NAME}_${LOCATION} +export NODE_SERVICE_PRINCIPAL=$(az aks show -g $RESOURCE_GROUP -n $AKS_NAME --query identityProfile.kubeletidentity.objectId | xargs echo) + +az role definition create --role-definition @${ROLE_DEFINITIN_FILE} +az role assignment create --assignee $NODE_SERVICE_PRINCIPAL --scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$NODES_RESOURCE_GROUP --role CodefreshDindVolumeProvisioner +``` + +Deploy Helm chart with the following values: + +`values.yaml` +```yaml +volumeProvisioner: + podSecurityContext: + enabled: true + runAsUser: 0 + runAsGroup: 0 + fsGroup: 0 + +storage: + backend: azuredisk + azuredisk: + availabilityZone: northeurope-1 # replace with your zone + resourceGroup: my-resource-group-name + + mountAzureJson: true + +runtime: + dind: + nodeSelector: + topology.kubernetes.io/zone: northeurope-1 +``` + +### GCE Disks backend volume configuration in GKE + +`dind-volume-provisioner` should have `ComputeEngine.StorageAdmin` permissions + +There are three options: + +1. Run `dind-volume-provisioner` pod on the node/node-group with IAM Service Account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +2. Pass static credentials in `.Values.storage.gcedisk.serviceAccountJson` (inline) or `.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef` (from your own secret) + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: | + { + "type": "service_account", + "project_id": "...", + "private_key_id": "...", + "private_key": "...", + "client_email": "...", + "client_id": "...", + "auth_uri": "...", + "token_uri": "...", + "auth_provider_x509_cert_url": "...", + "client_x509_cert_url": "..." + } + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g.: + # serviceAccountJsonSecretKeyRef: + # name: gce-service-account + # key: service-account.json + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +3. Assign IAM role to `dind-volume-provisioner` service account + +```yaml +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: gcedisk + + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "`pd-standard" + # -- Set GCP volume availability zone + availabilityZone: "us-central1-c" + +volumeProvisioner: + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Additional service account annotations + annotations: + iam.gke.io/gcp-service-account: @.iam.gserviceaccount.com + +# -- Set runtime parameters +runtime: + # -- Parameters for DinD (docker-in-docker) pod + dind: + # -- Set node selector. + nodeSelector: + topology.kubernetes.io/zone: us-central1-c +``` + +### Custom global environment variables + +You can add your own environment variables to the runtime environment. All pipeline steps have access to the global variables. + +```yaml +runtime: + engine: + userEnvVars: + - name: GITHUB_TOKEN + valueFrom: + secretKeyRef: + name: github-token + key: token +``` + +### Volume reuse policy + +Volume reuse behavior depends on the configuration for `reuseVolumeSelector` in the runtime environment spec. + +```yaml +runtime: + dind: + pvcs: + - name: dind + ... + reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName' + reuseVolumeSortOrder: pipeline_id +``` + +The following options are available: +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName'` - PV can be used by ANY pipeline in the specified account (default). +Benefit: Fewer PVs, resulting in lower costs. Since any PV can be used by any pipeline, the cluster needs to maintain/reserve fewer PVs in its PV pool for Codefresh. +Downside: Since the PV can be used by any pipeline, the PVs could have assets and info from different pipelines, reducing the probability of cache. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,project_id'` - PV can be used by ALL pipelines in your account, assigned to the same project. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id'` - PV can be used only by a single pipeline. +Benefit: More probability of cache without “spam” from other pipelines. +Downside: More PVs to maintain and therefore higher costs. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,io.codefresh.branch_name'` - PV can be used only by single pipeline AND single branch. + +- `reuseVolumeSelector: 'codefresh-app,io.codefresh.accountName,pipeline_id,trigger'` - PV can be used only by single pipeline AND single trigger. + +### Volume cleaners + +Codefresh pipelines require disk space for: + * [Pipeline Shared Volume](https://codefresh.io/docs/docs/pipelines/introduction-to-codefresh-pipelines/#sharing-the-workspace-between-build-steps) (`/codefresh/volume`, implemented as [docker volume](https://docs.docker.com/storage/volumes/)) + * Docker containers, both running and stopped + * Docker images and cached layers + +Codefresh offers two options to manage disk space and prevent out-of-space errors: +* Use runtime cleaners on Docker images and volumes +* [Set the minimum disk space per pipeline build volume](https://codefresh.io/docs/docs/pipelines/pipelines/#set-minimum-disk-space-for-a-pipeline-build) + +To improve performance by using Docker cache, Codefresh `volume-provisioner` can provision previously used disks with Docker images and pipeline volumes from previously run builds. + +### Types of runtime volume cleaners + +Docker images and volumes must be cleaned on a regular basis. + +* [IN-DIND cleaner](https://github.com/codefresh-io/dind/tree/master/cleaner): Deletes extra Docker containers, volumes, and images in **DIND pod**. +* [External volume cleaner](https://github.com/codefresh-io/dind-volume-cleanup): Deletes unused **external** PVs (EBS, GCE/Azure disks). +* [Local volume cleaner](https://github.com/codefresh-io/dind-volume-utils/blob/master/local-volumes/lv-cleaner.sh): Deletes **local** volumes if node disk space is close to the threshold. + +### IN-DIND cleaner + +**Purpose:** Removes unneeded *docker containers, images, volumes* inside Kubernetes volume mounted on the DIND pod + +**How it runs:** Inside each DIND pod as script + +**Triggered by:** SIGTERM and also during the run when disk usage > 90% (configurable) + +**Configured by:** Environment Variables which can be set in Runtime Environment spec + +**Configuration/Logic:** [README.md](https://github.com/codefresh-io/dind/tree/master/cleaner#readme) + +Override `.Values.runtime.dind.env` if necessary (the following are **defaults**): + +```yaml +runtime: + dind: + env: + CLEAN_PERIOD_SECONDS: '21600' # launch clean if last clean was more than CLEAN_PERIOD_SECONDS seconds ago + CLEAN_PERIOD_BUILDS: '5' # launch clean if last clean was more CLEAN_PERIOD_BUILDS builds since last build + IMAGE_RETAIN_PERIOD: '14400' # do not delete docker images if they have events since current_timestamp - IMAGE_RETAIN_PERIOD + VOLUMES_RETAIN_PERIOD: '14400' # do not delete docker volumes if they have events since current_timestamp - VOLUMES_RETAIN_PERIOD + DISK_USAGE_THRESHOLD: '0.8' # launch clean based on current disk usage DISK_USAGE_THRESHOLD + INODES_USAGE_THRESHOLD: '0.8' # launch clean based on current inodes usage INODES_USAGE_THRESHOLD +``` + +### External volumes cleaner + +**Purpose:** Removes unused *kubernetes volumes and related backend volumes* + +**How it runs:** Runs as `dind-volume-cleanup` CronJob. Installed in case the Runner uses non-local volumes `.Values.storage.backend != local` + +**Triggered by:** CronJob every 10min (configurable) + +**Configuration:** + +Set `codefresh.io/volume-retention` for dinds' PVCs: + +```yaml +runtime: + dind: + pvcs: + dind: + ... + annotations: + codefresh.io/volume-retention: 7d +``` + +Or override environment variables for `dind-volume-cleanup` cronjob: + +```yaml +volumeProvisioner: + dind-volume-cleanup: + env: + RETENTION_DAYS: 7 # clean volumes that were last used more than `RETENTION_DAYS` (default is 4) ago +``` + +### Local volumes cleaner + +**Purpose:** Deletes local volumes when node disk space is close to the threshold + +**How it runs:** Runs as `dind-lv-monitor` DaemonSet. Installed in case the Runner uses local volumes `.Values.storage.backend == local` + +**Triggered by:** Disk space usage or inode usage that exceeds thresholds (configurable) + +**Configuration:** + +Override environment variables for `dind-lv-monitor` daemonset: + +```yaml +volumeProvisioner: + dind-lv-monitor: + env: + KB_USAGE_THRESHOLD: 60 # default 80 (percentage) + INODE_USAGE_THRESHOLD: 60 # default 80 +``` + +### Rootless DinD + +DinD pod runs a `priviliged` container with **rootfull** docker. +To run the docker daemon as non-root user (**rootless** mode), change dind image tag: + +`values.yaml` +```yaml +runtime: + dind: + image: + tag: rootless +``` + +### ARM + +With the Codefresh Runner, you can run native ARM64v8 builds. + +> **Note!** +> You cannot run both amd64 and arm64 images within the same pipeline. As one pipeline can map only to one runtime, you can run either amd64 or arm64 within the same pipeline. + +Provide `nodeSelector` and(or) `tolerations` for dind pods: + +`values.yaml` +```yaml +runtime: + dind: + nodeSelector: + arch: arm64 + tolerations: + - key: arch + operator: Equal + value: arm64 + effect: NoSchedule +``` + +### Openshift + +To install Codefresh Runner on OpenShift use the following `values.yaml` example + +```yaml +runner: + podSecurityContext: + enabled: false + +volumeProvisioner: + podSecurityContext: + enabled: false + env: + PRIVILEGED_CONTAINER: true + dind-lv-monitor: + containerSecurityContext: + enabled: true + privileged: true + volumePermissions: + enabled: true + securityContext: + privileged: true + runAsUser: auto +``` + +Grant `privileged` SCC to `cf-runtime-runner` and `cf-runtime-volume-provisioner` service accounts. + +```console +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-runner + +oc adm policy add-scc-to-user privileged system:serviceaccount:codefresh:cf-runtime-volume-provisioner +``` + +### On-premise + +If you have [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) deployed, you can install Codefresh Runner in **agentless** mode. + +**What is agentless mode?** + +Agent (aka venona) is Runner component which responsible for calling Codefresh API to run builds and create dind/engine pods and pvc objects. Agent can only be assigned to a single account, thus you can't share one runtime across multiple accounts. However, with **agentless** mode it's possible to register the runtime as **system**-type runtime so it's registered on the platform level and can be assigned/shared across multiple accounts. + +**What are the prerequisites?** +- You have a running [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) control-plane environment +- You have a Codefresh API token with platform **Admin** permissions scope + + +### How to deploy agentless runtime when it's on the SAME k8s cluster as On-Premises control-plane environment? + +- Enable cluster-level permissions for cf-api (On-Premises control-plane component) + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) Helm chart +```yaml +cfapi: + ... + # -- Enable ClusterRole/ClusterRoleBinding + rbac: + namespaced: false +``` + +- Set the following values for Runner Helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=true` + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + runtimeName: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: true + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to check the runtime. Assign it to the required account(s). Run test pipeline on it. + + +### How to deploy agentless runtime when it's on the DIFFERENT k8s cluster than On-Premises control-plane environment? + +In this case, it's required to mount runtime cluster's `KUBECONFIG` into On-Premises `cf-api` deployment + +- Create the neccessary RBAC resources + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart +```yaml +extraResources: +- apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: codefresh-role + namespace: '{{ "{{ .Release.Namespace }}" }}' + rules: + - apiGroups: [""] + resources: ["pods", "persistentvolumeclaims", "persistentvolumes"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] + - apiGroups: ["snapshot.storage.k8s.io"] + resources: ["volumesnapshots"] + verbs: ["list", "watch", "get", "create", "patch", "delete"] +- apiVersion: v1 + kind: ServiceAccount + metadata: + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' +- apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: codefresh-role + subjects: + - kind: ServiceAccount + name: codefresh-runtime-user + namespace: '{{ "{{ .Release.Namespace }}" }}' +- apiVersion: v1 + kind: Secret + metadata: + name: codefresh-runtime-user-token + namespace: '{{ "{{ .Release.Namespace }}" }}' + annotations: + kubernetes.io/service-account.name: codefresh-runtime-user + type: kubernetes.io/service-account-token +``` + +- Set up the following environment variables to create a `KUBECONFIG` file + +```shell +NAMESPACE=cf-runtime +CLUSTER_NAME=prod-ue1-some-cluster-name +CURRENT_CONTEXT=$(kubectl config current-context) + +USER_TOKEN_VALUE=$(kubectl -n cf-runtime get secret/codefresh-runtime-user-token -o=go-template='{{ `{{.data.token}}` }}' | base64 --decode) +CURRENT_CLUSTER=$(kubectl config view --raw -o=go-template='{{ `{{range .contexts}}{{if eq .name "'''${CURRENT_CONTEXT}'''"}}{{ index .context "cluster" }}{{end}}{{end}}` }}') +CLUSTER_CA=$(kubectl config view --raw -o=go-template='{{ `{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}"{{with index .cluster "certificate-authority-data" }}{{.}}{{end}}"{{ end }}{{ end }}` }}') +CLUSTER_SERVER=$(kubectl config view --raw -o=go-template='{{ `{{range .clusters}}{{if eq .name "'''${CURRENT_CLUSTER}'''"}}{{ .cluster.server }}{{end}}{{ end }}` }}') + +export -p USER_TOKEN_VALUE CURRENT_CONTEXT CURRENT_CLUSTER CLUSTER_CA CLUSTER_SERVER CLUSTER_NAME +``` + +- Create a kubeconfig file + +```console +cat << EOF > $CLUSTER_NAME-kubeconfig +apiVersion: v1 +kind: Config +current-context: ${CLUSTER_NAME} +contexts: +- name: ${CLUSTER_NAME} + context: + cluster: ${CLUSTER_NAME} + user: codefresh-runtime-user + namespace: ${NAMESPACE} +clusters: +- name: ${CLUSTER_NAME} + cluster: + certificate-authority-data: ${CLUSTER_CA} + server: ${CLUSTER_SERVER} +users: +- name: ${CLUSTER_NAME} + user: + token: ${USER_TOKEN_VALUE} +EOF +``` + +- **Switch context to On-Premises control-plane cluster**. Create k8s secret (via any tool like [ESO](https://external-secrets.io/v0.4.4/), `kubectl`, etc ) containing runtime cluster's `KUBECONFG` created in previous step. + +```shell +NAMESPACE=codefresh +kubectl create secret generic dind-runtime-clusters --from-file=$CLUSTER_NAME=$CLUSTER_NAME-kubeconfig -n $NAMESPACE +``` + +- Mount secret containing runtime cluster's `KUBECONFG` into cf-api in On-Premises control-plane cluster + +> `values.yaml` for [Codefresh On-Premises](https://artifacthub.io/packages/helm/codefresh-onprem/codefresh) helm chart +```yaml +cf-api: + ... + volumes: + dind-clusters: + enabled: true + type: secret + nameOverride: dind-runtime-clusters + optional: true +``` +> volumeMount `/etc/kubeconfig` is already configured in cf-api Helm chart template. No need to specify it. + +- Set the following values for Runner helm chart + +> `values.yaml` for [Codefresh Runner](https://artifacthub.io/packages/helm/codefresh-runner/cf-runtime) helm chart + +`.Values.global.codefreshHost=...` \ +`.Values.global.codefreshToken=...` \ +`.Values.global.runtimeName=system/...` \ +`.Values.runtime.agent=false` \ +`.Values.runtime.inCluster=false` + +**Important!** +`.Values.global.name` ("system/" prefix is ignored!) should match the cluster name (key in `dind-runtime-clusters` secret created previously) +```yaml +global: + # -- URL of Codefresh On-Premises Platform + codefreshHost: "https://myonprem.somedomain.com" + # -- User token in plain text with Admin permission scope + codefreshToken: "" + # -- User token that references an existing secret containing API key. + codefreshTokenSecretKeyRef: {} + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Distinguished runtime name + # (for On-Premise only; mandatory!) Must be prefixed with "system/..." + name: "system/prod-ue1-some-cluster-name" + +# -- Set runtime parameters +runtime: + # -- (for On-Premise only; mandatory!) Disable agent + agent: false + # -- (for On-Premise only; optional) Set inCluster runtime (default: `true`) + # `inCluster=true` flag is set when Runtime and On-Premises control-plane are run on the same cluster + # `inCluster=false` flag is set when Runtime and On-Premises control-plane are on different clusters + inCluster: false + # -- (for On-Premise only; optional) Assign accounts to runtime (list of account ids; default is empty) + # Accounts can be assigned to the runtime in Codefresh UI later so you can kepp it empty. + accounts: [] + # -- (optional) Set parent runtime to inherit. + runtimeExtends: [] +``` + +- Install the chart + +```console +helm upgrade --install cf-runtime oci://quay.io/codefresh/cf-runtime -f values.yaml --create-namespace --namespace cf-runtime +``` + +- Verify the runtime and run test pipeline + +Go to [https:///admin/runtime-environments/system](https:///admin/runtime-environments/system) to see the runtime. Assign it to the required account(s). + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + diff --git a/charts/codefresh/cf-runtime/6.3.52/files/cleanup-runtime.sh b/charts/codefresh/cf-runtime/6.3.52/files/cleanup-runtime.sh new file mode 100644 index 000000000..c1fc5f368 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/files/cleanup-runtime.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +echo "-----" +echo "API_HOST: ${API_HOST}" +echo "AGENT_NAME: ${AGENT_NAME}" +echo "RUNTIME_NAME: ${RUNTIME_NAME}" +echo "AGENT: ${AGENT}" +echo "AGENT_SECRET_NAME: ${AGENT_SECRET_NAME}" +echo "DIND_SECRET_NAME: ${DIND_SECRET_NAME}" +echo "-----" + +auth() { + codefresh auth create-context --api-key ${API_TOKEN} --url ${API_HOST} +} + +remove_runtime() { + if [ "$AGENT" == "true" ]; then + codefresh delete re ${RUNTIME_NAME} || true + else + codefresh delete sys-re ${RUNTIME_NAME} || true + fi +} + +remove_agent() { + codefresh delete agent ${AGENT_NAME} || true +} + +remove_secrets() { + kubectl patch secret $(kubectl get secret -l codefresh.io/internal=true | awk 'NR>1{print $1}' | xargs) -p '{"metadata":{"finalizers":null}}' --type=merge || true + kubectl delete secret $AGENT_SECRET_NAME || true + kubectl delete secret $DIND_SECRET_NAME || true +} + +auth +remove_runtime +remove_agent +remove_secrets \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/files/configure-dind-certs.sh b/charts/codefresh/cf-runtime/6.3.52/files/configure-dind-certs.sh new file mode 100644 index 000000000..a1092eb1e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/files/configure-dind-certs.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# + +#--- +fatal() { + echo "ERROR: $1" + exit 1 +} + +msg() { echo -e "\e[32mINFO ---> $1\e[0m"; } +err() { echo -e "\e[31mERR ---> $1\e[0m" ; return 1; } + +exit_trap () { + local lc="$BASH_COMMAND" rc=$? + if [ $rc != 0 ]; then + if [[ -n "$SLEEP_ON_ERROR" ]]; then + echo -e "\nSLEEP_ON_ERROR is set - Sleeping to fix error" + sleep $SLEEP_ON_ERROR + fi + fi +} +trap exit_trap EXIT + +usage() { + echo "Usage: + $0 [-n | --namespace] [--server-cert-cn] [--server-cert-extra-sans] codefresh-api-host codefresh-api-token + +Example: + $0 -n workflow https://g.codefresh.io 21341234.423141234.412431234 + +" +} + +# Args +while [[ $1 =~ ^(-(n|h)|--(namespace|server-cert-cn|server-cert-extra-sans|help)) ]] +do + key=$1 + value=$2 + + case $key in + -h|--help) + usage + exit + ;; + -n|--namespace) + NAMESPACE="$value" + shift + ;; + --server-cert-cn) + SERVER_CERT_CN="$value" + shift + ;; + --server-cert-extra-sans) + SERVER_CERT_EXTRA_SANS="$value" + shift + ;; + esac + shift # past argument or value +done + +API_HOST=${1:-"$CF_API_HOST"} +API_TOKEN=${2:-"$CF_API_TOKEN"} + +[[ -z "$API_HOST" ]] && usage && fatal "Missing API_HOST" +[[ -z "$API_TOKEN" ]] && usage && fatal "Missing token" + + +API_SIGN_PATH=${API_SIGN_PATH:-"api/custom_clusters/signServerCerts"} + +NAMESPACE=${NAMESPACE:-default} +RELEASE=${RELEASE:-cf-runtime} + +DIR=$(dirname $0) +TMPDIR=/tmp/codefresh/ + +TMP_CERTS_FILE_ZIP=$TMPDIR/cf-certs.zip +TMP_CERTS_HEADERS_FILE=$TMPDIR/cf-certs-response-headers.txt +CERTS_DIR=$TMPDIR/ssl +SRV_TLS_CA_CERT=${CERTS_DIR}/ca.pem +SRV_TLS_KEY=${CERTS_DIR}/server-key.pem +SRV_TLS_CSR=${CERTS_DIR}/server-cert.csr +SRV_TLS_CERT=${CERTS_DIR}/server-cert.pem +CF_SRV_TLS_CERT=${CERTS_DIR}/cf-server-cert.pem +CF_SRV_TLS_CA_CERT=${CERTS_DIR}/cf-ca.pem +mkdir -p $TMPDIR $CERTS_DIR + +K8S_CERT_SECRET_NAME=codefresh-certs-server +echo -e "\n------------------\nGenerating server tls certificates ... " + +SERVER_CERT_CN=${SERVER_CERT_CN:-"docker.codefresh.io"} +SERVER_CERT_EXTRA_SANS="${SERVER_CERT_EXTRA_SANS}" +### + + openssl genrsa -out $SRV_TLS_KEY 4096 || fatal "Failed to generate openssl key " + openssl req -subj "/CN=${SERVER_CERT_CN}" -new -key $SRV_TLS_KEY -out $SRV_TLS_CSR || fatal "Failed to generate openssl csr " + GENERATE_CERTS=true + CSR=$(sed ':a;N;$!ba;s/\n/\\n/g' ${SRV_TLS_CSR}) + + SERVER_CERT_SANS="IP:127.0.0.1,DNS:dind,DNS:*.dind.${NAMESPACE},DNS:*.dind.${NAMESPACE}.svc${KUBE_DOMAIN},DNS:*.cf-cd.com,DNS:*.codefresh.io" + if [[ -n "${SERVER_CERT_EXTRA_SANS}" ]]; then + SERVER_CERT_SANS=${SERVER_CERT_SANS},${SERVER_CERT_EXTRA_SANS} + fi + echo "{\"reqSubjectAltName\": \"${SERVER_CERT_SANS}\", \"csr\": \"${CSR}\" }" > ${TMPDIR}/sign_req.json + + rm -fv ${TMP_CERTS_HEADERS_FILE} ${TMP_CERTS_FILE_ZIP} + + SIGN_STATUS=$(curl -k -sSL -d @${TMPDIR}/sign_req.json -H "Content-Type: application/json" -H "Authorization: ${API_TOKEN}" -H "Expect: " \ + -o ${TMP_CERTS_FILE_ZIP} -D ${TMP_CERTS_HEADERS_FILE} -w '%{http_code}' ${API_HOST}/${API_SIGN_PATH} ) + + echo "Sign request completed with HTTP_STATUS_CODE=$SIGN_STATUS" + if [[ $SIGN_STATUS != 200 ]]; then + echo "ERROR: Cannot sign certificates" + if [[ -f ${TMP_CERTS_FILE_ZIP} ]]; then + mv ${TMP_CERTS_FILE_ZIP} ${TMP_CERTS_FILE_ZIP}.error + cat ${TMP_CERTS_FILE_ZIP}.error + fi + exit 1 + fi + unzip -o -d ${CERTS_DIR}/ ${TMP_CERTS_FILE_ZIP} || fatal "Failed to unzip certificates to ${CERTS_DIR} " + cp -v ${CF_SRV_TLS_CA_CERT} $SRV_TLS_CA_CERT || fatal "received ${TMP_CERTS_FILE_ZIP} does not contains ca.pem" + cp -v ${CF_SRV_TLS_CERT} $SRV_TLS_CERT || fatal "received ${TMP_CERTS_FILE_ZIP} does not contains cf-server-cert.pem" + + +echo -e "\n------------------\nCreating certificate secret " + +kubectl -n $NAMESPACE create secret generic $K8S_CERT_SECRET_NAME \ + --from-file=$SRV_TLS_CA_CERT \ + --from-file=$SRV_TLS_KEY \ + --from-file=$SRV_TLS_CERT \ + --dry-run=client -o yaml | kubectl apply --overwrite -f - +kubectl -n $NAMESPACE label --overwrite secret ${K8S_CERT_SECRET_NAME} codefresh.io/internal=true +kubectl -n $NAMESPACE patch secret $K8S_CERT_SECRET_NAME -p '{"metadata": {"finalizers": ["kubernetes"]}}' diff --git a/charts/codefresh/cf-runtime/6.3.52/files/init-runtime.sh b/charts/codefresh/cf-runtime/6.3.52/files/init-runtime.sh new file mode 100644 index 000000000..eb3488af1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/files/init-runtime.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +echo "-----" +echo "API_HOST: ${API_HOST}" +echo "AGENT_NAME: ${AGENT_NAME}" +echo "KUBE_CONTEXT: ${KUBE_CONTEXT}" +echo "KUBE_NAMESPACE: ${KUBE_NAMESPACE}" +echo "OWNER_NAME: ${OWNER_NAME}" +echo "RUNTIME_NAME: ${RUNTIME_NAME}" +echo "SECRET_NAME: ${SECRET_NAME}" +echo "-----" + +create_agent_secret() { + + kubectl apply -f - < $1\e[0m"; } +err() { echo -e "\e[31mERR ---> $1\e[0m" ; return 1; } + + +if [ -z "${USER_CODEFRESH_TOKEN}" ]; then + err "missing codefresh user token. must supply \".global.codefreshToken\" if agent-codefresh-token does not exist" + exit 1 +fi + +codefresh auth create-context --api-key ${USER_CODEFRESH_TOKEN} --url ${API_HOST} + +while true; do + msg "Reconciling ${RUNTIME_NAME} runtime" + + sleep $RECONCILE_INTERVAL + + codefresh get re \ + --name ${RUNTIME_NAME} \ + -o yaml \ + | yq 'del(.version, .metadata.changedBy, .metadata.creationTime)' > /tmp/runtime.yaml + + kubectl get cm ${CONFIGMAP_NAME} -n ${KUBE_NAMESPACE} -o yaml \ + | yq 'del(.metadata.resourceVersion, .metadata.uid)' \ + | yq eval '.data["runtime.yaml"] = load_str("/tmp/runtime.yaml")' \ + | kubectl apply -f - +done diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_deployment.yaml new file mode 100644 index 000000000..26f3576b7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_deployment.yaml @@ -0,0 +1,70 @@ +{{- define "app-proxy.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "app-proxy.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "app-proxy.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "app-proxy.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: app-proxy + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include "app-proxy.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 3000 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /health + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_env-vars.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_env-vars.yaml new file mode 100644 index 000000000..c9b9a0e36 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_env-vars.yaml @@ -0,0 +1,19 @@ +{{- define "app-proxy.environment-variables.defaults" }} +PORT: 3000 +{{- end }} + +{{- define "app-proxy.environment-variables.calculated" }} +CODEFRESH_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +{{- with .Values.ingress.pathPrefix }} +API_PATH_PREFIX: {{ . | quote }} +{{- end }} +{{- end }} + +{{- define "app-proxy.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "app-proxy.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "app-proxy.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_helpers.tpl new file mode 100644 index 000000000..2d4272ca9 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "app-proxy.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "app-proxy" | 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 "app-proxy.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "app-proxy" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "app-proxy.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: app-proxy +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "app-proxy.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: app-proxy +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "app-proxy.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "app-proxy.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_ingress.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_ingress.yaml new file mode 100644 index 000000000..d7860b363 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_ingress.yaml @@ -0,0 +1,32 @@ +{{- define "app-proxy.resources.ingress" -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: {{- include "app-proxy.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.class (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.class }} + {{- end }} + {{- if .Values.ingress.tlsSecret }} + tls: + - hosts: + - {{ .Values.ingress.host }} + secretName: {{ .Values.tlsSecret }} + {{- end }} + rules: + - host: {{ .Values.ingress.host }} + http: + paths: + - path: {{ .Values.ingress.pathPrefix | default "/" }} + pathType: ImplementationSpecific + backend: + service: + name: {{ include "app-proxy.fullname" . }} + port: + number: 80 +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_rbac.yaml new file mode 100644 index 000000000..87bd869ba --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_rbac.yaml @@ -0,0 +1,47 @@ +{{- define "app-proxy.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "app-proxy.serviceAccountName" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "RoleBinding" "ClusterRoleBinding" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "app-proxy.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ include "app-proxy.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_service.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_service.yaml new file mode 100644 index 000000000..4c3a93bf2 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/app-proxy/_service.yaml @@ -0,0 +1,17 @@ +{{- define "app-proxy.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "app-proxy.fullname" . }} + labels: + {{- include "app-proxy.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 3000 + selector: + {{- include "app-proxy.selectorLabels" . | nindent 4 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_deployment.yaml new file mode 100644 index 000000000..62588b4d3 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_deployment.yaml @@ -0,0 +1,62 @@ +{{- define "event-exporter.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "event-exporter.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "event-exporter.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "event-exporter.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: event-exporter + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + args: [--running-in-cluster=true] + env: + {{- include "event-exporter.environment-variables" . | nindent 8 }} + ports: + - name: metrics + containerPort: 9102 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_env-vars.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_env-vars.yaml new file mode 100644 index 000000000..d28d0776f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_env-vars.yaml @@ -0,0 +1,14 @@ +{{- define "event-exporter.environment-variables.defaults" }} +{{- end }} + +{{- define "event-exporter.environment-variables.calculated" }} +{{- end }} + +{{- define "event-exporter.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "event-exporter.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "event-exporter.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_helpers.tpl new file mode 100644 index 000000000..5b8b5eff7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_helpers.tpl @@ -0,0 +1,43 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "event-exporter.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "event-exporter" | 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 "event-exporter.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "event-exporter" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "event-exporter.labels" -}} +{{ include "cf-runtime.labels" . }} +app: event-exporter +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "event-exporter.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +app: event-exporter +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "event-exporter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "event-exporter.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_rbac.yaml new file mode 100644 index 000000000..69d7b6b2f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_rbac.yaml @@ -0,0 +1,47 @@ +{{- define "event-exporter.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "event-exporter.serviceAccountName" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: [events] + verbs: [get, list, watch] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "event-exporter.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "event-exporter.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_service.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_service.yaml new file mode 100644 index 000000000..6fa29ec1a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_service.yaml @@ -0,0 +1,17 @@ +{{- define "event-exporter.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: metrics + port: 9102 + targetPort: metrics + protocol: TCP + selector: + {{- include "event-exporter.selectorLabels" . | nindent 4 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_serviceMontor.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_serviceMontor.yaml new file mode 100644 index 000000000..6092443f0 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/event-exporter/_serviceMontor.yaml @@ -0,0 +1,14 @@ +{{- define "event-exporter.resources.serviceMonitor" -}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "event-exporter.fullname" . }} + labels: + {{- include "event-exporter.labels" . | nindent 4 }} +spec: + endpoints: + - port: metrics + selector: + matchLabels: + {{- include "event-exporter.selectorLabels" . | nindent 6 }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_deployment.yaml new file mode 100644 index 000000000..7efa6557b --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_deployment.yaml @@ -0,0 +1,70 @@ +{{- define "monitor.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "monitor.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "monitor.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "monitor.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: monitor + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include "monitor.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 9020 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /api/ping + port: 9020 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_env-vars.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_env-vars.yaml new file mode 100644 index 000000000..f58c7fa25 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_env-vars.yaml @@ -0,0 +1,26 @@ +{{- define "monitor.environment-variables.defaults" }} +SERVICE_NAME: {{ include "monitor.fullname" . }} +PORT: 9020 +HELM3: true +NODE_OPTIONS: "--max_old_space_size=4096" +{{- end }} + +{{- define "monitor.environment-variables.calculated" }} +API_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +CLUSTER_ID: {{ include "runtime.runtime-environment-spec.context-name" . }} +API_URL: {{ include "runtime.runtime-environment-spec.codefresh-host" . }}/api/k8s-monitor/events +ACCOUNT_ID: {{ .Values.global.accountId }} +NAMESPACE: {{ .Release.Namespace }} +{{- if .Values.rbac.namespaced }} +ROLE_BINDING: true +{{- end }} +{{- end }} + +{{- define "monitor.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "monitor.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "monitor.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_helpers.tpl new file mode 100644 index 000000000..71cc1c027 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "monitor.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "monitor" | 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 "monitor.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "monitor" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "monitor.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: monitor +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "monitor.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: monitor +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "monitor.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "monitor.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_rbac.yaml new file mode 100644 index 000000000..88204796a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_rbac.yaml @@ -0,0 +1,56 @@ +{{- define "monitor.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "monitor.serviceAccountName" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch", "create", "delete" ] + - apiGroups: [ "" ] + resources: [ "pods" ] + verbs: [ "get", "list", "watch", "create", "deletecollection" ] + - apiGroups: [ "extensions" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "apps" ] + resources: [ "*" ] + verbs: [ "get", "list", "watch" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: {{ .Values.rbac.namespaced | ternary "RoleBinding" "ClusterRoleBinding" }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "monitor.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: {{ .Values.rbac.namespaced | ternary "Role" "ClusterRole" }} + name: {{ include "monitor.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_service.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_service.yaml new file mode 100644 index 000000000..f6ae9bb0f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/monitor/_service.yaml @@ -0,0 +1,17 @@ +{{- define "monitor.resources.service" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "monitor.fullname" . }} + labels: + {{- include "monitor.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 9020 + selector: + {{- include "monitor.selectorLabels" . | nindent 4 }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_deployment.yaml new file mode 100644 index 000000000..e1fb9439a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_deployment.yaml @@ -0,0 +1,103 @@ +{{- define "runner.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "runner.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "runner.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "runner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + initContainers: + - name: init + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.init.image "context" .) }} + imagePullPolicy: {{ .Values.init.image.pullPolicy | default "IfNotPresent" }} + command: + - /bin/bash + args: + - -ec + - | {{ .Files.Get "files/init-runtime.sh" | nindent 10 }} + env: + {{- include "runner-init.environment-variables" . | nindent 8 }} + {{- with .Values.init.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + containers: + - name: runner + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "IfNotPresent" }} + env: + {{- include "runner.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 8080 + readinessProbe: + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + path: /health + port: http + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.extraVolumeMounts }} + volumeMounts: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.sidecar.enabled }} + - name: reconcile-runtime + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.sidecar.image "context" .) }} + imagePullPolicy: {{ .Values.sidecar.image.pullPolicy | default "IfNotPresent" }} + command: + - /bin/bash + args: + - -ec + - | {{ .Files.Get "files/reconcile-runtime.sh" | nindent 10 }} + env: + {{- include "runner-sidecar.environment-variables" . | nindent 8 }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.extraVolumes }} + volumes: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_helpers.tpl new file mode 100644 index 000000000..2608cb67e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_helpers.tpl @@ -0,0 +1,42 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "runner.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "runner" | 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 "runner.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "runner" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "runner.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: runner +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "runner.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: runner +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "runner.serviceAccountName" -}} + {{- if .Values.serviceAccount.create }} + {{- default (include "runner.fullname" .) .Values.serviceAccount.name }} + {{- else }} + {{- default "default" .Values.serviceAccount.name }} + {{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_rbac.yaml new file mode 100644 index 000000000..d95b958d5 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/_rbac.yaml @@ -0,0 +1,53 @@ +{{- define "runner.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runner.serviceAccountName" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "pods", "persistentvolumeclaims" ] + verbs: [ "get", "create", "delete", patch ] + - apiGroups: [ "" ] + resources: [ "configmaps", "secrets" ] + verbs: [ "get", "create", "update", patch ] + - apiGroups: [ "apps" ] + resources: [ "deployments" ] + verbs: [ "get" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "runner.fullname" . }} + labels: + {{- include "runner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "runner.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: {{ include "runner.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_init-container.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_init-container.yaml new file mode 100644 index 000000000..6dda110f7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_init-container.yaml @@ -0,0 +1,30 @@ +{{- define "runner-init.environment-variables.defaults" }} +HOME: /tmp +{{- end }} + +{{- define "runner-init.environment-variables.calculated" }} +AGENT_NAME: {{ include "runtime.runtime-environment-spec.agent-name" . }} +API_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +AGENT_CODEFRESH_TOKEN: + valueFrom: + secretKeyRef: + name: {{ include "runner.fullname" . }} + key: agent-codefresh-token + optional: true +EXISTING_AGENT_CODEFRESH_TOKEN: {{ include "runtime.agent-token-env-var-value" . | nindent 2 }} +KUBE_CONTEXT: {{ include "runtime.runtime-environment-spec.context-name" . }} +KUBE_NAMESPACE: {{ .Release.Namespace }} +OWNER_NAME: {{ include "runner.fullname" . }} +RUNTIME_NAME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +SECRET_NAME: {{ include "runner.fullname" . }} +USER_CODEFRESH_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +{{- end }} + +{{- define "runner-init.environment-variables" }} + {{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + {{- $defaults := (include "runner-init.environment-variables.defaults" . | fromYaml) }} + {{- $calculated := (include "runner-init.environment-variables.calculated" . | fromYaml) }} + {{- $overrides := .Values.env }} + {{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_main-container.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_main-container.yaml new file mode 100644 index 000000000..4d3f0304e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_main-container.yaml @@ -0,0 +1,28 @@ +{{- define "runner.environment-variables.defaults" }} +AGENT_MODE: InCluster +SELF_DEPLOYMENT_NAME: + valueFrom: + fieldRef: + fieldPath: metadata.name +{{- end }} + +{{- define "runner.environment-variables.calculated" }} +AGENT_ID: {{ include "runtime.runtime-environment-spec.agent-name" . }} +CODEFRESH_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +CODEFRESH_IN_CLUSTER_RUNTIME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +CODEFRESH_TOKEN: + valueFrom: + secretKeyRef: + name: {{ include "runner.fullname" . }} + key: agent-codefresh-token +DOCKER_REGISTRY: {{ .Values.global.imageRegistry }} +{{- end }} + +{{- define "runner.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "runner.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "runner.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_sidecar-container.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_sidecar-container.yaml new file mode 100644 index 000000000..3adcbe5d4 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/runner/environment-variables/_sidecar-container.yaml @@ -0,0 +1,22 @@ +{{- define "runner-sidecar.environment-variables.defaults" }} +HOME: /tmp +{{- end }} + +{{- define "runner-sidecar.environment-variables.calculated" }} +API_HOST: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} +USER_CODEFRESH_TOKEN: {{ include "runtime.installation-token-env-var-value" . | nindent 2 }} +KUBE_CONTEXT: {{ include "runtime.runtime-environment-spec.context-name" . }} +KUBE_NAMESPACE: {{ .Release.Namespace }} +OWNER_NAME: {{ include "runner.fullname" . }} +RUNTIME_NAME: {{ include "runtime.runtime-environment-spec.runtime-name" . }} +CONFIGMAP_NAME: {{ printf "%s-%s" (include "runtime.fullname" .) "spec" }} +{{- end }} + +{{- define "runner-sidecar.environment-variables" }} + {{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + {{- $defaults := (include "runner-sidecar.environment-variables.defaults" . | fromYaml) }} + {{- $calculated := (include "runner-sidecar.environment-variables.calculated" . | fromYaml) }} + {{- $overrides := .Values.sidecar.env }} + {{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_cronjob.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_cronjob.yaml new file mode 100644 index 000000000..20bd2d56e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_cronjob.yaml @@ -0,0 +1,58 @@ +{{- define "dind-volume-provisioner.resources.cronjob" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- if not (eq .Values.storage.backend "local") }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "dind-volume-cleanup.fullname" . }} + labels: + {{- include "dind-volume-cleanup.labels" . | nindent 4 }} +spec: + concurrencyPolicy: {{ .Values.concurrencyPolicy }} + schedule: {{ .Values.schedule | quote }} + successfulJobsHistoryLimit: {{ .Values.successfulJobsHistory }} + failedJobsHistoryLimit: {{ .Values.failedJobsHistory }} + {{- with .Values.suspend }} + suspend: {{ . }} + {{- end }} + jobTemplate: + spec: + template: + metadata: + labels: + {{- include "dind-volume-cleanup.selectorLabels" . | nindent 12 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 12 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 10 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + restartPolicy: {{ .Values.restartPolicy | default "Never" }} + containers: + - name: dind-volume-cleanup + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + env: + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" .Values.env "context" .) | nindent 12 }} + - name: PROVISIONED_BY + value: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} + resources: + {{- toYaml .Values.resources | nindent 14 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_daemonset.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_daemonset.yaml new file mode 100644 index 000000000..cb463231d --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_daemonset.yaml @@ -0,0 +1,98 @@ +{{- define "dind-volume-provisioner.resources.daemonset" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $localVolumeParentDir := .Values.storage.local.volumeParentDir }} +{{- if eq .Values.storage.backend "local" }} +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "dind-lv-monitor.fullname" . }} + labels: + {{- include "dind-lv-monitor.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "dind-lv-monitor.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "dind-lv-monitor.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.volumePermissions.enabled }} + initContainers: + - name: volume-permissions + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.volumePermissions.image "context" .) }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | default "Always" }} + command: + - /bin/sh + args: + - -ec + - | + chown -R {{ .Values.podSecurityContext.runAsUser }}:{{ .Values.podSecurityContext.fsGroup }} {{ $localVolumeParentDir }} + volumeMounts: + - mountPath: {{ $localVolumeParentDir }} + name: dind-volume-dir + {{- if eq ( toString ( .Values.volumePermissions.securityContext.runAsUser )) "auto" }} + securityContext: {{- omit .Values.volumePermissions.securityContext "runAsUser" | toYaml | nindent 10 }} + {{- else }} + securityContext: {{- .Values.volumePermissions.securityContext | toYaml | nindent 10 }} + {{- end }} + resources: + {{- toYaml .Values.volumePermissions.resources | nindent 10 }} + {{- end }} + containers: + - name: dind-lv-monitor + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 10 }} + {{- end }} + command: + - /home/dind-volume-utils/bin/local-volumes-agent + env: + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" .Values.env "context" .) | nindent 10 }} + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: VOLUME_PARENT_DIR + value: {{ $localVolumeParentDir }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + volumeMounts: + - mountPath: {{ $localVolumeParentDir }} + readOnly: false + name: dind-volume-dir + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + - name: dind-volume-dir + hostPath: + path: {{ $localVolumeParentDir }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_deployment.yaml new file mode 100644 index 000000000..9252b4520 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_deployment.yaml @@ -0,0 +1,67 @@ +{{- define "dind-volume-provisioner.resources.deployment" -}} +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicasCount }} + strategy: + type: {{ .Values.updateStrategy.type }} + selector: + matchLabels: + {{- include "dind-volume-provisioner.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "dind-volume-provisioner.selectorLabels" . | nindent 8 }} + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include (printf "%s.image.pullSecrets" $cfCommonTplSemver ) . | nindent 8 }} + serviceAccountName: {{ include "dind-volume-provisioner.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + containers: + - name: dind-volume-provisioner + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy | default "Always" }} + command: + - /usr/local/bin/dind-volume-provisioner + - -v=4 + - --resync-period=50s + env: + {{- include "dind-volume-provisioner.environment-variables" . | nindent 8 }} + ports: + - name: http + containerPort: 8080 + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + {{- include "dind-volume-provisioner.volumeMounts.calculated" . | nindent 8 }} + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + volumes: + {{- include "dind-volume-provisioner.volumes.calculated" . | nindent 6 }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_env-vars.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_env-vars.yaml new file mode 100644 index 000000000..e1f5dfe60 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_env-vars.yaml @@ -0,0 +1,88 @@ +{{- define "dind-volume-provisioner.environment-variables.defaults" }} +{{- end }} + +{{- define "dind-volume-provisioner.environment-variables.calculated" }} +DOCKER_REGISTRY: {{ .Values.global.imageRegistry }} +PROVISIONER_NAME: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} + +{{- if or .Values.storage.ebs.accessKeyId .Values.storage.ebs.accessKeyIdSecretKeyRef }} +AWS_ACCESS_KEY_ID: + {{- if .Values.storage.ebs.accessKeyId }} + valueFrom: + secretKeyRef: + name: {{ include "dind-volume-provisioner.fullname" . }} + key: aws_access_key_id + {{- else if .Values.storage.ebs.accessKeyIdSecretKeyRef }} + valueFrom: + secretKeyRef: + {{- .Values.storage.ebs.accessKeyIdSecretKeyRef | toYaml | nindent 6 }} + {{- end }} +{{- end }} + +{{- if or .Values.storage.ebs.secretAccessKey .Values.storage.ebs.secretAccessKeySecretKeyRef }} +AWS_SECRET_ACCESS_KEY: + {{- if .Values.storage.ebs.secretAccessKey }} + valueFrom: + secretKeyRef: + name: {{ include "dind-volume-provisioner.fullname" . }} + key: aws_secret_access_key + {{- else if .Values.storage.ebs.secretAccessKeySecretKeyRef }} + valueFrom: + secretKeyRef: + {{- .Values.storage.ebs.secretAccessKeySecretKeyRef | toYaml | nindent 6 }} + {{- end }} +{{- end }} + +{{- if or .Values.storage.gcedisk.serviceAccountJson .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +GOOGLE_APPLICATION_CREDENTIALS: {{ printf "/etc/dind-volume-provisioner/credentials/%s" (.Values.storage.gcedisk.serviceAccountJsonSecretKeyRef.key | default "google-service-account.json") }} +{{- end }} + +{{- if and .Values.storage.mountAzureJson }} +AZURE_CREDENTIAL_FILE: /etc/kubernetes/azure.json +CLOUDCONFIG_AZURE: /etc/kubernetes/azure.json +{{- end }} + +{{- end }} + +{{- define "dind-volume-provisioner.environment-variables" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{- $defaults := (include "dind-volume-provisioner.environment-variables.defaults" . | fromYaml) }} +{{- $calculated := (include "dind-volume-provisioner.environment-variables.calculated" . | fromYaml) }} +{{- $overrides := .Values.env }} +{{- $mergedValues := mergeOverwrite (merge $defaults $calculated) $overrides }} +{{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $mergedValues "context" .) }} +{{- end }} + + +{{- define "dind-volume-provisioner.volumes.calculated" }} + {{- if .Values.storage.gcedisk.serviceAccountJson }} +- name: credentials + secret: + secretName: {{ include "dind-volume-provisioner.fullname" . }} + optional: true + {{- else if .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +- name: credentials + secret: + secretName: {{ .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef.name }} + optional: true + {{- end }} + {{- if .Values.storage.mountAzureJson }} +- name: azure-json + hostPath: + path: /etc/kubernetes/azure.json + type: File + {{- end }} +{{- end }} + +{{- define "dind-volume-provisioner.volumeMounts.calculated" }} + {{- if or .Values.storage.gcedisk.serviceAccountJson .Values.storage.gcedisk.serviceAccountJsonSecretKeyRef }} +- name: credentials + readOnly: true + mountPath: "/etc/dind-volume-provisioner/credentials" + {{- end }} + {{- if .Values.storage.mountAzureJson }} +- name: azure-json + readOnly: true + mountPath: "/etc/kubernetes/azure.json" + {{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_helpers.tpl new file mode 100644 index 000000000..e3d3a0d3f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_helpers.tpl @@ -0,0 +1,93 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "dind-volume-provisioner.name" -}} + {{- printf "%s-%s" (include "cf-runtime.name" .) "volume-provisioner" | 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 "dind-volume-provisioner.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "volume-provisioner" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "dind-volume-cleanup.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "volume-cleanup" | trunc 52 | trimSuffix "-" }} +{{- end }} + +{{- define "dind-lv-monitor.fullname" -}} + {{- printf "%s-%s" (include "cf-runtime.fullname" .) "lv-monitor" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Provisioner name for storage class +*/}} +{{- define "dind-volume-provisioner.volumeProvisionerName" }} + {{- printf "codefresh.io/dind-volume-provisioner-runner-%s" .Release.Namespace }} +{{- end }} + +{{/* +Common labels for dind-lv-monitor +*/}} +{{- define "dind-lv-monitor.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: lv-monitor +{{- end }} + +{{/* +Selector labels for dind-lv-monitor +*/}} +{{- define "dind-lv-monitor.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: lv-monitor +{{- end }} + +{{/* +Common labels for dind-volume-provisioner +*/}} +{{- define "dind-volume-provisioner.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: volume-provisioner +{{- end }} + +{{/* +Selector labels for dind-volume-provisioner +*/}} +{{- define "dind-volume-provisioner.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: volume-provisioner +{{- end }} + +{{/* +Common labels for dind-volume-cleanup +*/}} +{{- define "dind-volume-cleanup.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: pv-cleanup +{{- end }} + +{{/* +Common labels for dind-volume-cleanup +*/}} +{{- define "dind-volume-cleanup.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: pv-cleanup +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "dind-volume-provisioner.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "dind-volume-provisioner.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "dind-volume-provisioner.storageClassName" }} +{{- printf "dind-local-volumes-runner-%s" .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_rbac.yaml new file mode 100644 index 000000000..fbcbc684f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_rbac.yaml @@ -0,0 +1,71 @@ +{{- define "dind-volume-provisioner.resources.rbac" -}} +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "dind-volume-provisioner.serviceAccountName" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if .Values.rbac.create }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "persistentvolumes" ] + verbs: [ "get", "list", "watch", "create", "delete", "patch" ] + - apiGroups: [ "" ] + resources: [ "persistentvolumeclaims" ] + verbs: [ "get", "list", "watch", "update", "delete" ] + - apiGroups: [ "storage.k8s.io" ] + resources: [ "storageclasses" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "" ] + resources: [ "events" ] + verbs: [ "list", "watch", "create", "update", "patch" ] + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get", "list" ] + - apiGroups: [ "" ] + resources: [ "nodes" ] + verbs: [ "get", "list", "watch" ] + - apiGroups: [ "" ] + resources: [ "pods" ] + verbs: [ "get", "list", "watch", "create", "delete", "patch" ] + - apiGroups: [ "" ] + resources: [ "endpoints" ] + verbs: [ "get", "list", "watch", "create", "update", "delete" ] + - apiGroups: [ "coordination.k8s.io" ] + resources: [ "leases" ] + verbs: [ "get", "create", "update" ] +{{- with .Values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and .Values.serviceAccount.create .Values.rbac.create }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: {{ include "dind-volume-provisioner.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: {{ include "dind-volume-provisioner.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_secret.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_secret.yaml new file mode 100644 index 000000000..f361a7991 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_secret.yaml @@ -0,0 +1,22 @@ +{{- define "dind-volume-provisioner.resources.secret" -}} +{{- if or .Values.storage.ebs.accessKeyId .Values.storage.ebs.secretAccessKey .Values.storage.gcedisk.serviceAccountJson }} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ include "dind-volume-provisioner.fullname" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +stringData: + {{- with .Values.storage.gcedisk.serviceAccountJson }} + google-service-account.json: | +{{- . | nindent 4 }} + {{- end }} + {{- with .Values.storage.ebs.accessKeyId }} + aws_access_key_id: {{ . }} + {{- end }} + {{- with .Values.storage.ebs.secretAccessKey }} + aws_secret_access_key: {{ . }} + {{- end }} +{{- end }} +{{- end -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_storageclass.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_storageclass.yaml new file mode 100644 index 000000000..62e910c87 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_components/volume-provisioner/_storageclass.yaml @@ -0,0 +1,47 @@ +{{- define "dind-volume-provisioner.resources.storageclass" -}} +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + {{/* has to be exactly that */}} + name: {{ include "dind-volume-provisioner.storageClassName" . }} + labels: + {{- include "dind-volume-provisioner.labels" . | nindent 4 }} +provisioner: {{ include "dind-volume-provisioner.volumeProvisionerName" . }} +parameters: +{{- if eq .Values.storage.backend "local" }} + volumeBackend: local + volumeParentDir: {{ .Values.storage.local.volumeParentDir }} +{{- else if eq .Values.storage.backend "gcedisk" }} + volumeBackend: {{ .Values.storage.backend }} + type: {{ .Values.storage.gcedisk.volumeType | default "pd-ssd" }} + zone: {{ required ".Values.storage.gcedisk.availabilityZone is required" .Values.storage.gcedisk.availabilityZone }} + fsType: {{ .Values.storage.fsType | default "ext4" }} +{{- else if or (eq .Values.storage.backend "ebs") (eq .Values.storage.backend "ebs-csi")}} + volumeBackend: {{ .Values.storage.backend }} + VolumeType: {{ .Values.storage.ebs.volumeType | default "gp3" }} + AvailabilityZone: {{ required ".Values.storage.ebs.availabilityZone is required" .Values.storage.ebs.availabilityZone }} + fsType: {{ .Values.storage.fsType | default "ext4" }} + encrypted: {{ .Values.storage.ebs.encrypted | default "false" | quote }} + {{- with .Values.storage.ebs.kmsKeyId }} + kmsKeyId: {{ . | quote }} + {{- end }} + {{- with .Values.storage.ebs.iops }} + iops: {{ . | quote }} + {{- end }} + {{- with .Values.storage.ebs.throughput }} + throughput: {{ . | quote }} + {{- end }} +{{- else if or (eq .Values.storage.backend "azuredisk") (eq .Values.storage.backend "azuredisk-csi")}} + volumeBackend: {{ .Values.storage.backend }} + kind: managed + skuName: {{ .Values.storage.azuredisk.skuName | default "Premium_LRS" }} + fsType: {{ .Values.storage.fsType | default "ext4" }} + cachingMode: {{ .Values.storage.azuredisk.cachingMode | default "None" }} + {{- with .Values.storage.azuredisk.availabilityZone }} + availabilityZone: {{ . | quote }} + {{- end }} + {{- with .Values.storage.azuredisk.resourceGroup }} + resourceGroup: {{ . | quote }} + {{- end }} +{{- end }} +{{- end -}} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.52/templates/_helpers.tpl new file mode 100644 index 000000000..72f44e36a --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cf-runtime.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 "cf-runtime.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 "cf-runtime.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cf-runtime.labels" -}} +helm.sh/chart: {{ include "cf-runtime.chart" . }} +{{ include "cf-runtime.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cf-runtime.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cf-runtime.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/deployment.yaml new file mode 100644 index 000000000..90341b305 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/deployment.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.deployment" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/ingress.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/ingress.yaml new file mode 100644 index 000000000..56ab5e95e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/ingress.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.ingress" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/rbac.yaml new file mode 100644 index 000000000..4db87dcb4 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/rbac.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.rbac" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/service.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/service.yaml new file mode 100644 index 000000000..0b9d85ec0 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/app-proxy/service.yaml @@ -0,0 +1,9 @@ +{{- $appProxyContext := deepCopy . }} +{{- $_ := set $appProxyContext "Values" (get .Values "appProxy") }} +{{- $_ := set $appProxyContext.Values "global" (get .Values "global") }} +{{- $_ := set $appProxyContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $appProxyContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $appProxyContext.Values.enabled }} +{{- include "app-proxy.resources.service" $appProxyContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/deployment.yaml new file mode 100644 index 000000000..494288240 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/deployment.yaml @@ -0,0 +1,9 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.deployment" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/rbac.yaml new file mode 100644 index 000000000..6a9bf5c65 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/rbac.yaml @@ -0,0 +1,9 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.rbac" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/service.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/service.yaml new file mode 100644 index 000000000..c5d856dfe --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/event-exporter/service.yaml @@ -0,0 +1,11 @@ +{{- $eventExporterContext := deepCopy . }} +{{- $_ := set $eventExporterContext "Values" (get .Values "event-exporter") }} +{{- $_ := set $eventExporterContext.Values "global" (get .Values "global") }} +{{- $_ := set $eventExporterContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $eventExporterContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $eventExporterContext.Values.enabled }} +{{- include "event-exporter.resources.service" $eventExporterContext }} +--- +{{- include "event-exporter.resources.serviceMonitor" $eventExporterContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/extra/extra-resources.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/extra/extra-resources.yaml new file mode 100644 index 000000000..1a9777c64 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/extra/extra-resources.yaml @@ -0,0 +1,6 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} + +{{- range .Values.extraResources }} +--- +{{ include (printf "%s.tplrender" $cfCommonTplSemver) (dict "Values" . "context" $) }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/extra/runtime-images-cm.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/extra/runtime-images-cm.yaml new file mode 100644 index 000000000..f269c84b2 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/extra/runtime-images-cm.yaml @@ -0,0 +1,19 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.engine.runtimeImages }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + {{- /* dummy template just to list runtime images */}} + name: {{ include "runtime.fullname" . }}-images + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +data: + images: | + {{- range $key, $val := $values }} + image: {{ $val }} + {{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/cm-update-runtime.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/cm-update-runtime.yaml new file mode 100644 index 000000000..46a306c56 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/cm-update-runtime.yaml @@ -0,0 +1,18 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if $values.enabled }} +--- +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ include "runtime.fullname" . }}-spec + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +data: + runtime.yaml: | + {{ include "runtime.runtime-environment-spec.template" . | nindent 4 | trim }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/job-gencerts-dind.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/job-gencerts-dind.yaml new file mode 100644 index 000000000..4a08a229c --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/job-gencerts-dind.yaml @@ -0,0 +1,68 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.gencerts }} +{{- if and $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "3" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + {{- if $values.rbac.enabled }} + serviceAccountName: {{ template "runtime.fullname" . }}-gencerts-dind + {{- end }} + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: gencerts-dind + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | {{ .Files.Get "files/configure-dind-certs.sh" | nindent 10 }} + env: + - name: NAMESPACE + value: {{ .Release.Namespace }} + - name: RELEASE + value: {{ .Release.Name }} + - name: CF_API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + - name: CF_API_TOKEN + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/job-update-runtime.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/job-update-runtime.yaml new file mode 100644 index 000000000..955e882d7 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/job-update-runtime.yaml @@ -0,0 +1,77 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-patch + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-weight: "5" + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-patch + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: patch-runtime + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | + codefresh auth create-context --api-key $API_KEY --url $API_HOST + cat /usr/share/extras/runtime.yaml + codefresh get re +{{- if .Values.runtime.agent }} + codefresh patch re -f /usr/share/extras/runtime.yaml +{{- else }} + codefresh patch sys-re -f /usr/share/extras/runtime.yaml +{{- end }} + env: + - name: API_KEY + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + - name: API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + volumeMounts: + - name: config + mountPath: /usr/share/extras/runtime.yaml + subPath: runtime.yaml + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure + volumes: + - name: config + configMap: + name: {{ include "runtime.fullname" . }}-spec +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/rbac-gencerts-dind.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/rbac-gencerts-dind.yaml new file mode 100644 index 000000000..4907dac38 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/post-install/rbac-gencerts-dind.yaml @@ -0,0 +1,37 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.gencerts }} +{{- if and $values.enabled }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - "" + resources: + - secrets + - configmaps + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "runtime.fullname" . }}-gencerts-dind +subjects: + - kind: ServiceAccount + name: {{ include "runtime.fullname" . }}-gencerts-dind + namespace: {{ .Release.Namespace }} +{{ end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/hooks/pre-delete/job-cleanup-resources.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/pre-delete/job-cleanup-resources.yaml new file mode 100644 index 000000000..0e3c7659f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/pre-delete/job-cleanup-resources.yaml @@ -0,0 +1,73 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if and $values.enabled }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + labels: + {{- include "runtime.labels" . | nindent 4 }} + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + {{- with $values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with $values.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ . }} + {{- end }} + {{- with $values.backoffLimit }} + backoffLimit: {{ . | int }} + {{- end }} + template: + metadata: + name: {{ include "runtime.fullname" . }}-cleanup + labels: + {{- include "runtime.labels" . | nindent 8 }} + spec: + {{- if $values.rbac.enabled }} + serviceAccountName: {{ template "runtime.fullname" . }}-cleanup + {{- end }} + securityContext: + {{- toYaml $values.podSecurityContext | nindent 8 }} + containers: + - name: cleanup + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $values.image "context" .) }} + imagePullPolicy: {{ $values.image.pullPolicy | default "Always" }} + command: + - "/bin/bash" + args: + - -ec + - | {{ .Files.Get "files/cleanup-runtime.sh" | nindent 10 }} + env: + - name: AGENT_NAME + value: {{ include "runtime.runtime-environment-spec.agent-name" . }} + - name: RUNTIME_NAME + value: {{ include "runtime.runtime-environment-spec.runtime-name" . }} + - name: API_HOST + value: {{ include "runtime.runtime-environment-spec.codefresh-host" . }} + - name: API_TOKEN + {{- include "runtime.installation-token-env-var-value" . | indent 10}} + - name: AGENT + value: {{ .Values.runtime.agent | quote }} + - name: AGENT_SECRET_NAME + value: {{ include "runner.fullname" . }} + - name: DIND_SECRET_NAME + value: codefresh-certs-server + {{- include (printf "%s.env-vars" $cfCommonTplSemver) (dict "Values" $values.env "context" .) | nindent 8 }} + {{- with $values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $values.tolerations }} + tolerations: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/hooks/pre-delete/rbac-cleanup-resources.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/pre-delete/rbac-cleanup-resources.yaml new file mode 100644 index 000000000..468ec2212 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/hooks/pre-delete/rbac-cleanup-resources.yaml @@ -0,0 +1,46 @@ +{{ $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version }} +{{ $values := .Values.runtime.patch }} +{{- if and $values.enabled }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +rules: + - apiGroups: + - "*" + resources: + - "*" + verbs: + - "*" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation,hook-failed +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "runtime.fullname" . }}-cleanup +subjects: + - kind: ServiceAccount + name: {{ include "runtime.fullname" . }}-cleanup + namespace: {{ .Release.Namespace }} +{{ end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/monitor/deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/monitor/deployment.yaml new file mode 100644 index 000000000..00c9fb2f9 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/monitor/deployment.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.deployment" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/monitor/rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/monitor/rbac.yaml new file mode 100644 index 000000000..f9812d565 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/monitor/rbac.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.rbac" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/monitor/service.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/monitor/service.yaml new file mode 100644 index 000000000..f99706614 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/monitor/service.yaml @@ -0,0 +1,9 @@ +{{- $monitorContext := deepCopy . }} +{{- $_ := set $monitorContext "Values" (get .Values "monitor") }} +{{- $_ := set $monitorContext.Values "global" (get .Values "global") }} +{{- $_ := set $monitorContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $monitorContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $monitorContext.Values.enabled }} +{{- include "monitor.resources.service" $monitorContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/other/external-secrets.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/other/external-secrets.yaml new file mode 100644 index 000000000..dc24e24e5 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/other/external-secrets.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.external-secrets" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/other/podMonitor.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/other/podMonitor.yaml new file mode 100644 index 000000000..4319b722b --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/other/podMonitor.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.podMonitor" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/other/serviceMonitor.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/other/serviceMonitor.yaml new file mode 100644 index 000000000..29f890fe2 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/other/serviceMonitor.yaml @@ -0,0 +1,2 @@ +{{ $templateName := printf "cf-common-%s.serviceMonitor" (index .Subcharts "cf-common").Chart.Version }} +{{- include $templateName . -}} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/runner/deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/runner/deployment.yaml new file mode 100644 index 000000000..85777c487 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/runner/deployment.yaml @@ -0,0 +1,9 @@ +{{- $runnerContext := deepCopy . }} +{{- $_ := set $runnerContext "Values" (get .Values "runner") }} +{{- $_ := set $runnerContext.Values "global" (get .Values "global") }} +{{- $_ := set $runnerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $runnerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $runnerContext.Values.enabled .Values.runtime.agent }} +{{- include "runner.resources.deployment" $runnerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/runner/rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/runner/rbac.yaml new file mode 100644 index 000000000..d5f8c1323 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/runner/rbac.yaml @@ -0,0 +1,9 @@ +{{- $runnerContext := deepCopy . }} +{{- $_ := set $runnerContext "Values" (get .Values "runner") }} +{{- $_ := set $runnerContext.Values "global" (get .Values "global") }} +{{- $_ := set $runnerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $runnerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $runnerContext.Values.enabled .Values.runtime.agent }} +{{- include "runner.resources.rbac" $runnerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/runtime/_helpers.tpl b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/_helpers.tpl new file mode 100644 index 000000000..6ba04fcc3 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/_helpers.tpl @@ -0,0 +1,123 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "runtime.name" -}} + {{- printf "%s" (include "cf-runtime.name" .) | 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 "runtime.fullname" -}} + {{- printf "%s" (include "cf-runtime.fullname" .) | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "runtime.labels" -}} +{{ include "cf-runtime.labels" . }} +codefresh.io/application: runtime +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "runtime.selectorLabels" -}} +{{ include "cf-runtime.selectorLabels" . }} +codefresh.io/application: runtime +{{- end }} + +{{/* +Return runtime image (classic runtime) with private registry prefix +*/}} +{{- define "runtime.runtimeImageName" -}} + {{- if .registry -}} + {{- $imageName := (trimPrefix "quay.io/" .imageFullName) -}} + {{- printf "%s/%s" .registry $imageName -}} + {{- else -}} + {{- printf "%s" .imageFullName -}} + {{- end -}} +{{- end -}} + +{{/* +Environment variable value of Codefresh installation token +*/}} +{{- define "runtime.installation-token-env-var-value" -}} + {{- if .Values.global.codefreshToken }} +valueFrom: + secretKeyRef: + name: {{ include "runtime.installation-token-secret-name" . }} + key: codefresh-api-token + {{- else if .Values.global.codefreshTokenSecretKeyRef }} +valueFrom: + secretKeyRef: + {{- .Values.global.codefreshTokenSecretKeyRef | toYaml | nindent 4 }} + {{- end }} +{{- end }} + +{{/* +Environment variable value of Codefresh agent token +*/}} +{{- define "runtime.agent-token-env-var-value" -}} + {{- if .Values.global.agentToken }} +{{- printf "%s" .Values.global.agentToken | toYaml }} + {{- else if .Values.global.agentTokenSecretKeyRef }} +valueFrom: + secretKeyRef: + {{- .Values.global.agentTokenSecretKeyRef | toYaml | nindent 4 }} + {{- end }} +{{- end }} + +{{/* +Print Codefresh API token secret name +*/}} +{{- define "runtime.installation-token-secret-name" }} +{{- print "codefresh-user-token" }} +{{- end }} + +{{/* +Print Codefresh host +*/}} +{{- define "runtime.runtime-environment-spec.codefresh-host" }} +{{- if and (not .Values.global.codefreshHost) }} + {{- fail "ERROR: .global.codefreshHost is required" }} +{{- else }} + {{- printf "%s" (trimSuffix "/" .Values.global.codefreshHost) }} +{{- end }} +{{- end }} + +{{/* +Print runtime-environment name +*/}} +{{- define "runtime.runtime-environment-spec.runtime-name" }} +{{- if and (not .Values.global.runtimeName) }} + {{- printf "%s/%s" .Values.global.context .Release.Namespace }} +{{- else }} + {{- printf "%s" .Values.global.runtimeName }} +{{- end }} +{{- end }} + +{{/* +Print agent name +*/}} +{{- define "runtime.runtime-environment-spec.agent-name" }} +{{- if and (not .Values.global.agentName) }} + {{- printf "%s_%s" .Values.global.context .Release.Namespace }} +{{- else }} + {{- printf "%s" .Values.global.agentName }} +{{- end }} +{{- end }} + +{{/* +Print context +*/}} +{{- define "runtime.runtime-environment-spec.context-name" }} +{{- if and (not .Values.global.context) }} + {{- fail "ERROR: .global.context is required" }} +{{- else }} + {{- printf "%s" .Values.global.context }} +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/runtime/cm-dind-daemon.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/cm-dind-daemon.yaml new file mode 100644 index 000000000..fc7f92905 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/cm-dind-daemon.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + {{- /* has to be a constant */}} + name: codefresh-dind-config + labels: + {{- include "runtime.labels" . | nindent 4 }} +data: + daemon.json: | +{{ coalesce .Values.re.dindDaemon .Values.runtime.dindDaemon | toPrettyJson | indent 4 }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/runtime/rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/rbac.yaml new file mode 100644 index 000000000..a51b12526 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/rbac.yaml @@ -0,0 +1,48 @@ +{{ $values := .Values.runtime }} +--- +{{- if or $values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- /* has to be a constant */}} + name: codefresh-engine + labels: + {{- include "runtime.labels" . | nindent 4 }} + {{- with $values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +--- +{{- if $values.rbac.create }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: codefresh-engine + labels: + {{- include "runner.labels" . | nindent 4 }} +rules: + - apiGroups: [ "" ] + resources: [ "secrets" ] + verbs: [ "get" ] +{{- with $values.rbac.rules }} + {{ toYaml . | nindent 2 }} +{{- end }} +{{- end }} +--- +{{- if and $values.serviceAccount.create $values.rbac.create }} +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: codefresh-engine + labels: + {{- include "runner.labels" . | nindent 4 }} +subjects: + - kind: ServiceAccount + name: codefresh-engine +roleRef: + kind: Role + name: codefresh-engine + apiGroup: rbac.authorization.k8s.io +{{- end }} + diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/runtime/runtime-env-spec-tmpl.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/runtime-env-spec-tmpl.yaml new file mode 100644 index 000000000..1e54e6a04 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/runtime-env-spec-tmpl.yaml @@ -0,0 +1,210 @@ +{{- define "runtime.runtime-environment-spec.template" }} +{{- $cfCommonTplSemver := printf "cf-common-%s" (index .Subcharts "cf-common").Chart.Version -}} +{{- $kubeconfigFilePath := (include "runtime.runtime-environment-spec.runtime-name" .) -}} +{{- $name := (include "runtime.runtime-environment-spec.runtime-name" .) -}} +{{- $engineContext := .Values.runtime.engine -}} +{{- $dindContext := .Values.runtime.dind -}} +{{- $imageRegistry := .Values.global.imageRegistry -}} +metadata: + name: {{ include "runtime.runtime-environment-spec.runtime-name" . }} + agent: {{ .Values.runtime.agent }} +runtimeScheduler: + type: KubernetesPod + {{- if $engineContext.image }} + image: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $engineContext.image "context" .) | squote }} + {{- end }} + imagePullPolicy: {{ $engineContext.image.pullPolicy }} + {{- with $engineContext.command }} + command: {{- toYaml . | nindent 4 }} + {{- end }} + envVars: + {{- with $engineContext.env }} + {{- range $key, $val := . }} + {{- if or (kindIs "bool" $val) (kindIs "int" $val) (kindIs "float64" $val) }} + {{ $key }}: {{ $val | squote }} + {{- else }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + COMPOSE_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.COMPOSE_IMAGE) | squote }} + CONTAINER_LOGGER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.CONTAINER_LOGGER_IMAGE) | squote }} + DOCKER_BUILDER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_BUILDER_IMAGE) | squote }} + DOCKER_PULLER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_PULLER_IMAGE) | squote }} + DOCKER_PUSHER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_PUSHER_IMAGE) | squote }} + DOCKER_TAG_PUSHER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.DOCKER_TAG_PUSHER_IMAGE) | squote }} + FS_OPS_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.FS_OPS_IMAGE) | squote }} + GIT_CLONE_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.GIT_CLONE_IMAGE) | squote }} + KUBE_DEPLOY: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.KUBE_DEPLOY) | squote }} + PIPELINE_DEBUGGER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.PIPELINE_DEBUGGER_IMAGE) | squote }} + TEMPLATE_ENGINE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.TEMPLATE_ENGINE) | squote }} + CR_6177_FIXER: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.CR_6177_FIXER) | squote }} + GC_BUILDER_IMAGE: {{ include "runtime.runtimeImageName" (dict "registry" $imageRegistry "imageFullName" $engineContext.runtimeImages.GC_BUILDER_IMAGE) | squote }} + {{- with $engineContext.userEnvVars }} + userEnvVars: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.workflowLimits }} + workflowLimits: {{- toYaml . | nindent 4 }} + {{- end }} + cluster: + namespace: {{ .Release.Namespace }} + serviceAccount: {{ $engineContext.serviceAccount }} + {{- if .Values.runtime.agent }} + clusterProvider: + accountId: {{ .Values.global.accountId }} + selector: {{ include "runtime.runtime-environment-spec.context-name" . }} + {{- else }} + {{- if .Values.runtime.inCluster }} + inCluster: true + kubeconfigFilePath: null + {{- else }} + name: {{ $name }} + kubeconfigFilePath: {{ printf "/etc/kubeconfig/%s" $kubeconfigFilePath }} + {{- end }} + {{- end }} + {{- with $engineContext.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with $engineContext.affinity }} + affinity: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.tolerations }} + tolerations: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $engineContext.podAnnotations }} + annotations: + {{- range $key, $val := . }} + {{ $key }}: {{ $val | squote }} + {{- end }} + {{- end }} + {{- with $engineContext.podLabels }} + labels: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $engineContext.schedulerName }} + schedulerName: {{ $engineContext.schedulerName }} + {{- end }} + resources: + {{- if $engineContext.resources}} + {{- toYaml $engineContext.resources | nindent 4 }} + {{- end }} +dockerDaemonScheduler: + type: DindKubernetesPod + {{- if $dindContext.image }} + dindImage: {{ include (printf "%s.image.name" $cfCommonTplSemver ) (dict "image" $dindContext.image "context" .) | squote }} + {{- end }} + imagePullPolicy: {{ $dindContext.image.pullPolicy }} + {{- with $dindContext.userAccess }} + userAccess: {{ . }} + {{- end }} + {{- with $dindContext.env }} + envVars: + {{- range $key, $val := . }} + {{- if or (kindIs "bool" $val) (kindIs "int" $val) (kindIs "float64" $val) }} + {{ $key }}: {{ $val | squote }} + {{- else }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- end }} + cluster: + namespace: {{ .Release.Namespace }} + serviceAccount: {{ $dindContext.serviceAccount }} + {{- if .Values.runtime.agent }} + clusterProvider: + accountId: {{ .Values.global.accountId }} + selector: {{ include "runtime.runtime-environment-spec.context-name" . }} + {{- else }} + {{- if .Values.runtime.inCluster }} + inCluster: true + kubeconfigFilePath: null + {{- else }} + name: {{ $name }} + kubeconfigFilePath: {{ printf "/etc/kubeconfig/%s" $kubeconfigFilePath }} + {{- end }} + {{- end }} + {{- with $dindContext.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with $dindContext.affinity }} + affinity: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.tolerations }} + tolerations: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.podAnnotations }} + annotations: + {{- range $key, $val := . }} + {{ $key }}: {{ $val | squote }} + {{- end }} + {{- end }} + {{- with $dindContext.podLabels }} + labels: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if $dindContext.schedulerName }} + schedulerName: {{ $dindContext.schedulerName }} + {{- end }} + {{- if $dindContext.pvcs }} + pvcs: + {{- range $index, $pvc := $dindContext.pvcs }} + - name: {{ $pvc.name }} + reuseVolumeSelector: {{ $pvc.reuseVolumeSelector | squote }} + reuseVolumeSortOrder: {{ $pvc.reuseVolumeSortOrder }} + storageClassName: {{ include (printf "%v.tplrender" $cfCommonTplSemver) (dict "Values" $pvc.storageClassName "context" $) }} + volumeSize: {{ $pvc.volumeSize }} + {{- with $pvc.annotations }} + annotations: {{ . | toYaml | nindent 8 }} + {{- end }} + {{- end }} + {{- end }} + defaultDindResources: + {{- with $dindContext.resources }} + {{- if not .requests }} + limits: {{- toYaml .limits | nindent 6 }} + requests: null + {{- else }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} + {{- with $dindContext.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ . }} + {{- end }} + {{- with $dindContext.userVolumeMounts }} + userVolumeMounts: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with $dindContext.userVolumes }} + userVolumes: {{- toYaml . | nindent 4 }} + {{- end }} + {{- if and (not .Values.runtime.agent) }} + clientCertPath: /etc/ssl/cf/ + volumeMounts: + codefresh-certs-server: + name: codefresh-certs-server + mountPath: /etc/ssl/cf + readOnly: false + volumes: + codefresh-certs-server: + name: codefresh-certs-server + secret: + secretName: codefresh-certs-server + {{- end }} +extends: {{- toYaml .Values.runtime.runtimeExtends | nindent 2 }} + {{- if .Values.runtime.description }} +description: {{ .Values.runtime.description }} + {{- else }} +description: null + {{- end }} +{{- if .Values.global.accountId }} +accountId: {{ .Values.global.accountId }} +{{- end }} +{{- if not .Values.runtime.agent }} +accounts: {{- toYaml .Values.runtime.accounts | nindent 2 }} +{{- end }} +{{- if .Values.appProxy.enabled }} +appProxy: + externalIP: >- + {{ printf "https://%s%s" .Values.appProxy.ingress.host (.Values.appProxy.ingress.pathPrefix | default "/") }} +{{- end }} +{{- if not .Values.runtime.agent }} +systemHybrid: true +{{- end }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/runtime/secret.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/secret.yaml new file mode 100644 index 000000000..2366d3ccf --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/secret.yaml @@ -0,0 +1,11 @@ +{{- if and .Values.global.codefreshToken }} +apiVersion: v1 +kind: Secret +type: Opaque +metadata: + name: {{ include "runtime.installation-token-secret-name" . }} + labels: + {{- include "runtime.labels" . | nindent 4 }} +stringData: + codefresh-api-token: {{ .Values.global.codefreshToken }} +{{- end }} \ No newline at end of file diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/runtime/svc-dind.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/svc-dind.yaml new file mode 100644 index 000000000..098edb4e8 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/runtime/svc-dind.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + {{- include "runtime.labels" . | nindent 4 }} + app: dind + {{/* has to be a constant */}} + name: dind +spec: + ports: + - name: "dind-port" + port: 1300 + protocol: TCP + clusterIP: None + selector: + app: dind diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/cronjob.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/cronjob.yaml new file mode 100644 index 000000000..db955bc77 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/cronjob.yaml @@ -0,0 +1,11 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values.volumeProvisioner "dind-volume-cleanup") }} +{{- $_ := set $volumeProvisionerContext.Values "serviceAccount" (get .Values.volumeProvisioner "serviceAccount") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $volumeProvisionerContext.Values.enabled .Values.volumeProvisioner.enabled }} +{{- include "dind-volume-provisioner.resources.cronjob" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/daemonset.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/daemonset.yaml new file mode 100644 index 000000000..39927149e --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/daemonset.yaml @@ -0,0 +1,11 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values.volumeProvisioner "dind-lv-monitor") }} +{{- $_ := set $volumeProvisionerContext.Values "serviceAccount" (get .Values.volumeProvisioner "serviceAccount") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if and $volumeProvisionerContext.Values.enabled .Values.volumeProvisioner.enabled }} +{{- include "dind-volume-provisioner.resources.daemonset" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/deployment.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/deployment.yaml new file mode 100644 index 000000000..522fa8791 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/deployment.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.deployment" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/rbac.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/rbac.yaml new file mode 100644 index 000000000..f3ae9609f --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/rbac.yaml @@ -0,0 +1,9 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.rbac" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/secret.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/secret.yaml new file mode 100644 index 000000000..accf601d1 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/secret.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.secret" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/storageclass.yaml b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/storageclass.yaml new file mode 100644 index 000000000..77a7602da --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/templates/volume-provisioner/storageclass.yaml @@ -0,0 +1,10 @@ +{{- $volumeProvisionerContext := deepCopy . }} +{{- $_ := set $volumeProvisionerContext "Values" (get .Values "volumeProvisioner") }} +{{- $_ := set $volumeProvisionerContext.Values "global" (get .Values "global") }} +{{- $_ := set $volumeProvisionerContext.Values "storage" (get .Values "storage") }} +{{- $_ := set $volumeProvisionerContext.Values "nameOverride" (get .Values "nameOverride") }} +{{- $_ := set $volumeProvisionerContext.Values "fullnameOverride" (get .Values "fullnameOverride") }} + +{{- if $volumeProvisionerContext.Values.enabled }} +{{- include "dind-volume-provisioner.resources.storageclass" $volumeProvisionerContext }} +{{- end }} diff --git a/charts/codefresh/cf-runtime/6.3.52/values.yaml b/charts/codefresh/cf-runtime/6.3.52/values.yaml new file mode 100644 index 000000000..23c2aa5c0 --- /dev/null +++ b/charts/codefresh/cf-runtime/6.3.52/values.yaml @@ -0,0 +1,946 @@ +# -- String to partially override cf-runtime.fullname template (will maintain the release name) +nameOverride: "" +# -- String to fully override cf-runtime.fullname template +fullnameOverride: "" + +# -- Global parameters +# @default -- See below +global: + # -- Global Docker image registry + imageRegistry: "" + # -- Global Docker registry secret names as array + imagePullSecrets: [] + + # -- URL of Codefresh Platform (required!) + codefreshHost: "https://g.codefresh.io" + # -- User token in plain text (required if `global.codefreshTokenSecretKeyRef` is omitted!) + # Ref: https://g.codefresh.io/user/settings (see API Keys) + # Minimal API key scopes: Runner-Installation(read+write), Agent(read+write), Agents(read+write) + codefreshToken: "" + # -- User token that references an existing secret containing API key (required if `global.codefreshToken` is omitted!) + codefreshTokenSecretKeyRef: {} + + # E.g. + # codefreshTokenSecretKeyRef: + # name: my-codefresh-api-token + # key: codefresh-api-token + + # -- Account ID (required!) + # Can be obtained here https://g.codefresh.io/2.0/account-settings/account-information + accountId: "" + + # -- K8s context name (required!) + context: "" + # E.g. + # context: prod-ue1-runtime-1 + + # -- Agent Name (optional!) + # If omitted, the following format will be used `{{ .Values.global.context }}_{{ .Release.Namespace }}` + agentName: "" + # E.g. + # agentName: prod-ue1-runtime-1 + + # -- Runtime name (optional!) + # If omitted, the following format will be used `{{ .Values.global.context }}/{{ .Release.Namespace }}` + runtimeName: "" + # E.g. + # runtimeName: prod-ue1-runtime-1/namespace + + # -- DEPRECATED Agent token in plain text. + # !!! MUST BE provided if migrating from < 6.x chart version + agentToken: "" + # -- DEPRECATED Agent token that references an existing secret containing API key. + # !!! MUST BE provided if migrating from < 6.x chart version + agentTokenSecretKeyRef: {} + # E.g. + # agentTokenSecretKeyRef: + # name: my-codefresh-agent-secret + # key: codefresh-agent-token + +# DEPRECATED -- Use `.Values.global.imageRegistry` instead +dockerRegistry: "" + +# DEPRECATED -- Use `.Values.runtime` instead +re: {} + +# -- Runner parameters +# @default -- See below +runner: + # -- Enable the runner + enabled: true + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/venona + tag: 1.10.2 + + # -- Init container + init: + image: + registry: quay.io + repository: codefresh/cli + tag: 0.85.0-rootless + + resources: + limits: + memory: 512Mi + cpu: '1' + requests: + memory: 256Mi + cpu: '0.2' + + # -- Sidecar container + # Reconciles runtime spec from Codefresh API for drift detection + sidecar: + enabled: false + image: + registry: quay.io + repository: codefresh/codefresh-shell + tag: 0.0.2 + env: + RECONCILE_INTERVAL: 300 + resources: {} + + # -- Add additional env vars + env: {} + # E.g. + # env: + # WORKFLOW_CONCURRENCY: 50 # The number of workflow creation and termination tasks the Runner can handle in parallel. Defaults to 50 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: true + runAsUser: 10001 + runAsGroup: 10001 + fsGroup: 10001 + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + # -- Set requests and limits + resources: {} + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Volume Provisioner parameters +# @default -- See below +volumeProvisioner: + # -- Enable volume-provisioner + enabled: true + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: Recreate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/dind-volume-provisioner + tag: 1.35.0 + # -- Add additional env vars + env: {} + # E.g. + # env: + # THREADINESS: 4 # The number of PVC requests the dind-volume-provisioner can process in parallel. Defaults to 4 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + # E.g. + # serviceAccount: + # annotations: + # eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: true + runAsUser: 3000 + runAsGroup: 3000 + fsGroup: 3000 + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + + # -- `dind-lv-monitor` DaemonSet parameters + # (local volumes cleaner) + # @default -- See below + dind-lv-monitor: + enabled: true + image: + registry: quay.io + repository: codefresh/dind-volume-utils + tag: 1.29.4 + podAnnotations: {} + podSecurityContext: + enabled: true + runAsUser: 1000 + fsGroup: 1000 + containerSecurityContext: {} + env: {} + resources: {} + nodeSelector: {} + tolerations: + - key: 'codefresh/dind' + operator: 'Exists' + effect: 'NoSchedule' + volumePermissions: + enabled: true + image: + registry: docker.io + repository: alpine + tag: 3.18 + resources: {} + securityContext: + runAsUser: 0 # auto + + # `dind-volume-cleanup` CronJob parameters + # (external volumes cleaner) + # @default -- See below + dind-volume-cleanup: + enabled: true + image: + registry: quay.io + repository: codefresh/dind-volume-cleanup + tag: 1.2.0 + env: {} + concurrencyPolicy: Forbid + schedule: "*/10 * * * *" + successfulJobsHistory: 3 + failedJobsHistory: 1 + suspend: false + podAnnotations: {} + podSecurityContext: + enabled: true + fsGroup: 3000 + runAsGroup: 3000 + runAsUser: 3000 + nodeSelector: {} + affinity: {} + tolerations: [] + +# Storage parameters for volume-provisioner +# @default -- See below +storage: + # -- Set backend volume type (`local`/`ebs`/`ebs-csi`/`gcedisk`/`azuredisk`) + backend: local + # -- Set filesystem type (`ext4`/`xfs`) + fsType: "ext4" + + # Storage parametrs example for local volumes on the K8S nodes filesystem (i.e. `storage.backend=local`) + # https://kubernetes.io/docs/concepts/storage/volumes/#local + # @default -- See below + local: + # -- Set volume path on the host filesystem + volumeParentDir: /var/lib/codefresh/dind-volumes + + # Storage parameters example for aws ebs disks (i.e. `storage.backend=ebs`/`storage.backend=ebs-csi`) + # https://aws.amazon.com/ebs/ + # https://codefresh.io/docs/docs/installation/codefresh-runner/#aws-backend-volume-configuration + # @default -- See below + ebs: + # -- Set EBS volume type (`gp2`/`gp3`/`io1`) (required) + volumeType: "gp2" + # -- Set EBS volumes availability zone (required) + availabilityZone: "us-east-1a" + # -- Enable encryption (optional) + encrypted: "false" + # -- Set KMS encryption key ID (optional) + kmsKeyId: "" + + # -- Set AWS_ACCESS_KEY_ID for volume-provisioner (optional) + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions + accessKeyId: "" + # -- Existing secret containing AWS_ACCESS_KEY_ID. + accessKeyIdSecretKeyRef: {} + # E.g. + # accessKeyIdSecretKeyRef: + # name: + # key: + + # -- Set AWS_SECRET_ACCESS_KEY for volume-provisioner (optional) + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#dind-volume-provisioner-permissions + secretAccessKey: "" + # -- Existing secret containing AWS_SECRET_ACCESS_KEY + secretAccessKeySecretKeyRef: {} + # E.g. + # secretAccessKeySecretKeyRef: + # name: + # key: + + # E.g. + # ebs: + # volumeType: gp3 + # availabilityZone: us-east-1c + # encrypted: false + # iops: "5000" + # # I/O operations per second. Only effetive when gp3 volume type is specified. + # # Default value - 3000. + # # Max - 16,000 + # throughput: "500" + # # Throughput in MiB/s. Only effective when gp3 volume type is specified. + # # Default value - 125. + # # Max - 1000. + # ebs: + # volumeType: gp2 + # availabilityZone: us-east-1c + # encrypted: true + # kmsKeyId: "1234abcd-12ab-34cd-56ef-1234567890ab" + # accessKeyId: "MYKEYID" + # secretAccessKey: "MYACCESSKEY" + + # Storage parameters example for gce disks + # https://cloud.google.com/compute/docs/disks#pdspecs + # https://codefresh.io/docs/docs/installation/codefresh-runner/#gke-google-kubernetes-engine-backend-volume-configuration + # @default -- See below + gcedisk: + # -- Set GCP volume backend type (`pd-ssd`/`pd-standard`) + volumeType: "pd-ssd" + # -- Set GCP volume availability zone + availabilityZone: "us-west1-a" + # -- Set Google SA JSON key for volume-provisioner (optional) + serviceAccountJson: "" + # -- Existing secret containing containing Google SA JSON key for volume-provisioner (optional) + serviceAccountJsonSecretKeyRef: {} + # E.g. + # gcedisk: + # volumeType: pd-ssd + # availabilityZone: us-central1-c + # serviceAccountJson: |- + # { + # "type": "service_account", + # "project_id": "...", + # "private_key_id": "...", + # "private_key": "...", + # "client_email": "...", + # "client_id": "...", + # "auth_uri": "...", + # "token_uri": "...", + # "auth_provider_x509_cert_url": "...", + # "client_x509_cert_url": "..." + # } + + # Storage parameters example for Azure Disks + # https://codefresh.io/docs/docs/installation/codefresh-runner/#install-codefresh-runner-on-azure-kubernetes-service-aks + # @default -- See below + azuredisk: + # -- Set storage type (`Premium_LRS`) + skuName: Premium_LRS + cachingMode: None + # availabilityZone: northeurope-1 + # resourceGroup: + # DiskIOPSReadWrite: 500 + # DiskMBpsReadWrite: 100 + + mountAzureJson: false + +# -- Set runtime parameters +# @default -- See below + +runtime: + # -- Set annotation on engine Service Account + # Ref: https://codefresh.io/docs/docs/administration/codefresh-runner/#injecting-aws-arn-roles-into-the-cluster + serviceAccount: + create: true + annotations: {} + # E.g. + # serviceAccount: + # annotations: + # eks.amazonaws.com/role-arn: "arn:aws:iam:::role/" + + # -- Set parent runtime to inherit. + # Should not be changes. Parent runtime is controlled from Codefresh side. + runtimeExtends: + - system/default/hybrid/k8s_low_limits + # -- Runtime description + description: "" + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the engine role + rules: [] + + # -- (for On-Premise only) Enable agent + agent: true + # -- (for On-Premise only) Set inCluster runtime + inCluster: true + # -- (for On-Premise only) Assign accounts to runtime (list of account ids) + accounts: [] + + # -- Parameters for DinD (docker-in-docker) pod (aka "runtime" pod). + dind: + # -- Set dind image. + image: + registry: quay.io + repository: codefresh/dind + tag: 26.1.4-1.28.7 # use `latest-rootless/rootless/26.1.4-1.28.7-rootless` tags for rootless-dind + pullPolicy: IfNotPresent + # -- Set dind resources. + resources: + requests: null + limits: + cpu: 400m + memory: 800Mi + # -- PV claim spec parametes. + pvcs: + # -- Default dind PVC parameters + dind: + # -- PVC name prefix. + # Keep `dind` as default! Don't change! + name: dind + # -- PVC storage class name. + # Change ONLY if you need to use storage class NOT from Codefresh volume-provisioner + storageClassName: '{{ include "dind-volume-provisioner.storageClassName" . }}' + # -- PVC size. + volumeSize: 16Gi + # -- PV reuse selector. + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#volume-reuse-policy + reuseVolumeSelector: codefresh-app,io.codefresh.accountName + reuseVolumeSortOrder: pipeline_id + # -- PV annotations. + annotations: {} + # E.g.: + # annotations: + # codefresh.io/volume-retention: 7d + # -- Set additional env vars. + env: + DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE: true + # -- Set pod annotations. + podAnnotations: {} + # -- Set pod labels. + podLabels: {} + # -- Set node selector. + nodeSelector: {} + # -- Set affinity + affinity: {} + # -- Set tolerations. + tolerations: [] + # -- Set scheduler name. + schedulerName: "" + # -- Set service account for pod. + serviceAccount: codefresh-engine + # -- Keep `true` as default! + userAccess: true + # -- Add extra volumes + userVolumes: {} + # E.g.: + # userVolumes: + # regctl-docker-registry: + # name: regctl-docker-registry + # secret: + # items: + # - key: .dockerconfigjson + # path: config.json + # secretName: regctl-docker-registry + # optional: true + # -- Add extra volume mounts + userVolumeMounts: {} + # E.g.: + # userVolumeMounts: + # regctl-docker-registry: + # name: regctl-docker-registry + # mountPath: /home/appuser/.docker/ + # readOnly: true + + # -- Parameters for Engine pod (aka "pipeline" orchestrator). + engine: + # -- Set image. + image: + registry: quay.io + repository: codefresh/engine + tag: 1.173.6 + pullPolicy: IfNotPresent + # -- Set container command. + command: + - npm + - run + - start + # -- Set resources. + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 1000m + memory: 2048Mi + # -- Set system(base) runtime images. + # @default -- See below. + runtimeImages: + COMPOSE_IMAGE: quay.io/codefresh/compose:v2.28.1-1.5.0 + CONTAINER_LOGGER_IMAGE: quay.io/codefresh/cf-container-logger:1.11.6 + DOCKER_BUILDER_IMAGE: quay.io/codefresh/cf-docker-builder:1.3.13 + DOCKER_PULLER_IMAGE: quay.io/codefresh/cf-docker-puller:8.0.17 + DOCKER_PUSHER_IMAGE: quay.io/codefresh/cf-docker-pusher:6.0.15 + DOCKER_TAG_PUSHER_IMAGE: quay.io/codefresh/cf-docker-tag-pusher:1.3.14 + FS_OPS_IMAGE: quay.io/codefresh/fs-ops:1.2.3 + GIT_CLONE_IMAGE: quay.io/codefresh/cf-git-cloner:10.1.26 + KUBE_DEPLOY: quay.io/codefresh/cf-deploy-kubernetes:16.1.11 + PIPELINE_DEBUGGER_IMAGE: quay.io/codefresh/cf-debugger:1.3.0 + TEMPLATE_ENGINE: quay.io/codefresh/pikolo:0.14.1 + CR_6177_FIXER: 'quay.io/codefresh/alpine:edge' + GC_BUILDER_IMAGE: 'quay.io/codefresh/cf-gc-builder:0.5.3' + # -- Set additional env vars. + env: + # -- Interval to check the exec status in the container-logger + CONTAINER_LOGGER_EXEC_CHECK_INTERVAL_MS: 1000 + # -- Timeout while doing requests to the Docker daemon + DOCKER_REQUEST_TIMEOUT_MS: 30000 + # -- If "true", composition images will be pulled sequentially + FORCE_COMPOSE_SERIAL_PULL: false + # -- Level of logging for engine + LOGGER_LEVEL: debug + # -- Enable debug-level logging of outgoing HTTP/HTTPS requests + LOG_OUTGOING_HTTP_REQUESTS: false + # -- Enable emitting metrics from engine + METRICS_PROMETHEUS_ENABLED: true + # -- Enable legacy metrics + METRICS_PROMETHEUS_ENABLE_LEGACY_METRICS: false + # -- Enable collecting process metrics + METRICS_PROMETHEUS_COLLECT_PROCESS_METRICS: false + # -- Host for Prometheus metrics server + METRICS_PROMETHEUS_HOST: '0.0.0.0' + # -- Port for Prometheus metrics server + METRICS_PROMETHEUS_PORT: 9100 + # -- Set workflow limits. + workflowLimits: + # -- Maximum time allowed to the engine to wait for the pre-steps (aka "Initializing Process") to succeed; seconds. + MAXIMUM_ALLOWED_TIME_BEFORE_PRE_STEPS_SUCCESS: 600 + # -- Maximum time for workflow execution; seconds. + MAXIMUM_ALLOWED_WORKFLOW_AGE_BEFORE_TERMINATION: 86400 + # -- Maximum time allowed to workflow to spend in "elected" state; seconds. + MAXIMUM_ELECTED_STATE_AGE_ALLOWED: 900 + # -- Maximum retry attempts allowed for workflow. + MAXIMUM_RETRY_ATTEMPTS_ALLOWED: 20 + # -- Maximum time allowed to workflow to spend in "terminating" state until force terminated; seconds. + MAXIMUM_TERMINATING_STATE_AGE_ALLOWED: 900 + # -- Maximum time allowed to workflow to spend in "terminating" state without logs activity until force terminated; seconds. + MAXIMUM_TERMINATING_STATE_AGE_ALLOWED_WITHOUT_UPDATE: 300 + # -- Time since the last health check report after which workflow is terminated; seconds. + TIME_ENGINE_INACTIVE_UNTIL_TERMINATION: 300 + # -- Time since the last health check report after which the engine is considered unhealthy; seconds. + TIME_ENGINE_INACTIVE_UNTIL_UNHEALTHY: 60 + # -- Time since the last workflow logs activity after which workflow is terminated; seconds. + TIME_INACTIVE_UNTIL_TERMINATION: 2700 + # -- Set pod annotations. + podAnnotations: {} + # -- Set pod labels. + podLabels: {} + # -- Set node selector. + nodeSelector: {} + # -- Set affinity + affinity: {} + # -- Set tolerations. + tolerations: [] + # -- Set scheduler name. + schedulerName: "" + # -- Set service account for pod. + serviceAccount: codefresh-engine + # -- Set extra env vars + userEnvVars: [] + # E.g. + # userEnvVars: + # - name: GITHUB_TOKEN + # valueFrom: + # secretKeyRef: + # name: github-token + # key: token + + # -- Parameters for `runtime-patch` post-upgrade/install hook + # @default -- See below + patch: + enabled: true + image: + registry: quay.io + repository: codefresh/cli + tag: 0.85.0-rootless + rbac: + enabled: true + annotations: {} + affinity: {} + nodeSelector: {} + podSecurityContext: {} + resources: {} + tolerations: [] + ttlSecondsAfterFinished: 180 + env: + HOME: /tmp + + # -- Parameters for `gencerts-dind` post-upgrade/install hook + # @default -- See below + gencerts: + enabled: true + image: + registry: quay.io + repository: codefresh/kubectl + tag: 1.28.4 + rbac: + enabled: true + annotations: {} + affinity: {} + nodeSelector: {} + podSecurityContext: {} + resources: {} + tolerations: [] + ttlSecondsAfterFinished: 180 + + # -- DinD pod daemon config + # @default -- See below + dindDaemon: + hosts: + - unix:///var/run/docker.sock + - tcp://0.0.0.0:1300 + tlsverify: true + tls: true + tlscacert: /etc/ssl/cf-client/ca.pem + tlscert: /etc/ssl/cf/server-cert.pem + tlskey: /etc/ssl/cf/server-key.pem + insecure-registries: + - 192.168.99.100:5000 + metrics-addr: 0.0.0.0:9323 + experimental: true + +# App-Proxy parameters +# Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#app-proxy-installation +# @default -- See below +appProxy: + # -- Enable app-proxy + enabled: false + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/cf-app-proxy + tag: 0.0.47 + # -- Add additional env vars + env: {} + + # Set app-proxy ingress parameters + # @default -- See below + ingress: + # -- Set path prefix for ingress (keep empty for default `/` path) + pathPrefix: "" + # -- Set ingress class + class: "" + # -- Set DNS hostname the ingress will use + host: "" + # -- Set k8s tls secret for the ingress object + tlsSecret: "" + # -- Set extra annotations for ingress object + annotations: {} + # E.g. + # ingress: + # pathPrefix: "/cf-app-proxy" + # class: "nginx" + # host: "mydomain.com" + # tlsSecret: "tls-cert-app-proxy" + # annotations: + # nginx.ingress.kubernetes.io/whitelist-source-range: 123.123.123.123/130 + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + podSecurityContext: {} + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + # -- Set requests and limits + resources: {} + # -- Set node selector + nodeSelector: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# Monitor parameters +# @default -- See below +monitor: + # -- Enable monitor + # Ref: https://codefresh.io/docs/docs/installation/codefresh-runner/#install-monitoring-component + enabled: false + + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: RollingUpdate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: quay.io + repository: codefresh/cf-k8s-agent + tag: 1.3.17 + # -- Add additional env vars + env: {} + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Use Role(true)/ClusterRole(true) + namespaced: true + # -- Add custom rule to the role + rules: [] + + # -- Readiness probe configuration + # @default -- See below + readinessProbe: + failureThreshold: 5 + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + + podSecurityContext: {} + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Add serviceMonitor +# @default -- See below +serviceMonitor: + main: + # -- Enable service monitor for dind pods + enabled: false + nameOverride: dind + selector: + matchLabels: + app: dind + endpoints: + - path: /metrics + targetPort: 9100 + relabelings: + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + +# -- Add podMonitor (for engine pods) +# @default -- See below +podMonitor: + main: + # -- Enable pod monitor for engine pods + enabled: false + nameOverride: engine + selector: + matchLabels: + app: runtime + podMetricsEndpoints: + - path: /metrics + targetPort: 9100 + + runner: + # -- Enable pod monitor for runner pod + enabled: false + nameOverride: runner + selector: + matchLabels: + codefresh.io/application: runner + podMetricsEndpoints: + - path: /metrics + targetPort: 8080 + + volume-provisioner: + # -- Enable pod monitor for volumeProvisioner pod + enabled: false + nameOverride: volume-provisioner + selector: + matchLabels: + codefresh.io/application: volume-provisioner + podMetricsEndpoints: + - path: /metrics + targetPort: 8080 + +# -- Event exporter parameters +# @default -- See below +event-exporter: + # -- Enable event-exporter + enabled: false + # -- Set number of pods + replicasCount: 1 + # -- Upgrade strategy + updateStrategy: + type: Recreate + # -- Set pod annotations + podAnnotations: {} + + # -- Set image + image: + registry: docker.io + repository: codefresh/k8s-event-exporter + tag: latest + # -- Add additional env vars + env: {} + + # -- Service Account parameters + serviceAccount: + # -- Create service account + create: true + # -- Override service account name + name: "" + # -- Additional service account annotations + annotations: {} + + # -- RBAC parameters + rbac: + # -- Create RBAC resources + create: true + # -- Add custom rule to the role + rules: [] + + # -- Set security context for the pod + # @default -- See below + podSecurityContext: + enabled: false + + # -- Set node selector + nodeSelector: {} + # -- Set resources + resources: {} + # -- Set tolerations + tolerations: [] + # -- Set affinity + affinity: {} + +# -- Array of extra objects to deploy with the release +extraResources: [] +# E.g. +# extraResources: +# - apiVersion: rbac.authorization.k8s.io/v1 +# kind: ClusterRole +# metadata: +# name: codefresh-role +# rules: +# - apiGroups: [ "*"] +# resources: ["*"] +# verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +# - apiVersion: v1 +# kind: ServiceAccount +# metadata: +# name: codefresh-user +# namespace: "{{ .Release.Namespace }}" +# - apiVersion: rbac.authorization.k8s.io/v1 +# kind: ClusterRoleBinding +# metadata: +# name: codefresh-user +# roleRef: +# apiGroup: rbac.authorization.k8s.io +# kind: ClusterRole +# name: codefresh-role +# subjects: +# - kind: ServiceAccount +# name: codefresh-user +# namespace: "{{ .Release.Namespace }}" +# - apiVersion: v1 +# kind: Secret +# type: kubernetes.io/service-account-token +# metadata: +# name: codefresh-user-token +# namespace: "{{ .Release.Namespace }}" +# annotations: +# kubernetes.io/service-account.name: "codefresh-user" diff --git a/charts/digitalis/vals-operator/0.7.10/.gitignore b/charts/digitalis/vals-operator/0.7.10/.gitignore new file mode 100644 index 000000000..d9f7c8d36 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/.gitignore @@ -0,0 +1,49 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Node artifact files +node_modules/ +dist/ + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Maven +target/ +dist/ + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv diff --git a/charts/digitalis/vals-operator/0.7.10/Chart.yaml b/charts/digitalis/vals-operator/0.7.10/Chart.yaml new file mode 100644 index 000000000..39bfaf23d --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Vals-Operator + catalog.cattle.io/kube-version: '>= 1.19.0-0' + catalog.cattle.io/release-name: vals-operator +apiVersion: v2 +appVersion: v0.7.10 +description: 'This helm chart installs the Digitalis Vals Operator to manage and sync + secrets from supported backends into Kubernetes. ## About Vals-Operator Here at + [Digitalis](https://digitalis.io) we love [vals](https://github.com/helmfile/vals), + it''s a tool we use daily to keep secrets stored securely. Inspired by this tool, + we have created an operator to manage Kubernetes secrets. *vals-operator* syncs + secrets from any secrets store supported by [vals](https://github.com/helmfile/vals) + into Kubernetes. Also, `vals-operator` supports database secrets as provider by + [HashiCorp Vault Secret Engine](https://developer.hashicorp.com/vault/docs/secrets/databases). ' +icon: file://assets/icons/vals-operator.png +kubeVersion: '>= 1.19.0-0' +maintainers: +- email: info@digitalis.io + name: Digitalis.IO +name: vals-operator +type: application +version: 0.7.10 diff --git a/charts/digitalis/vals-operator/0.7.10/README.md b/charts/digitalis/vals-operator/0.7.10/README.md new file mode 100644 index 000000000..6818acd03 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/README.md @@ -0,0 +1,55 @@ +# vals-operator + +![Version: 0.7.10](https://img.shields.io/badge/Version-0.7.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.7.10](https://img.shields.io/badge/AppVersion-v0.7.10-informational?style=flat-square) + +This helm chart installs the Digitalis Vals Operator to manage and sync secrets from supported backends into Kubernetes. +## About Vals-Operator +Here at [Digitalis](https://digitalis.io) we love [vals](https://github.com/helmfile/vals), it's a tool we use daily to keep secrets stored securely. Inspired by this tool, we have created an operator to manage Kubernetes secrets. +*vals-operator* syncs secrets from any secrets store supported by [vals](https://github.com/helmfile/vals) into Kubernetes. Also, `vals-operator` supports database secrets as provider by [HashiCorp Vault Secret Engine](https://developer.hashicorp.com/vault/docs/secrets/databases). + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| Digitalis.IO | | | + +## Requirements + +Kubernetes: `>= 1.19.0-0` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| args | list | `[]` | | +| enableDbSecrets | bool | `true` | | +| env | list | `[]` | | +| environmentSecret | string | `""` | | +| fullnameOverride | string | `""` | | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.repository | string | `"ghcr.io/digitalis-io/vals-operator"` | | +| image.tag | string | `""` | | +| imagePullSecrets | list | `[]` | | +| manageCrds | bool | `true` | | +| nameOverride | string | `""` | | +| nodeSelector | object | `{}` | | +| podMonitor.enabled | bool | `false` | | +| podMonitor.labels | object | `{}` | | +| podSecurityContext | object | `{}` | | +| prometheusRules.additionalRuleAnnotations | object | `{}` | | +| prometheusRules.additionalRuleLabels | object | `{}` | | +| prometheusRules.enabled | bool | `false` | | +| replicaCount | int | `1` | | +| resources | object | `{}` | | +| secretEnv | list | `[]` | | +| securityContext | object | `{}` | | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.create | bool | `true` | | +| serviceAccount.name | string | `""` | | +| tolerations | list | `[]` | | +| volumeMounts | list | `[]` | | +| volumes | list | `[]` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/charts/digitalis/vals-operator/0.7.10/app-readme.md b/charts/digitalis/vals-operator/0.7.10/app-readme.md new file mode 100644 index 000000000..3458f2059 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/app-readme.md @@ -0,0 +1,9 @@ +# Vals-Operator + +Here at [Digitalis](https://digitalis.io) we love [vals](https://github.com/variantdev/vals), it's a tool we use daily to keep secrets stored securely. We also use [secrets-manager](https://github.com/tuenti/secrets-manager) on the Kubernetes deployment we manage. Inspired by these two wonderful tools we have created this operator. + +*vals-operator* syncs secrets from any secrets store supported by [vals](https://github.com/variantdev/vals) into Kubernetes. It works very similarly to [secrets-manager](https://github.com/tuenti/secrets-manager) and the code is actually based on it. Where they differ is that it not just supports HashiCorp Vault but many other secrets stores. + +## Mirroring secrets + +We have also added the ability to copy secrets between namespaces. It uses the format `ref+k8s://namespace/secret#key`. This way you can keep secrets generated in one namespace in sync with any other namespace in the cluster. diff --git a/charts/digitalis/vals-operator/0.7.10/crds/dbsecrets.yaml b/charts/digitalis/vals-operator/0.7.10/crds/dbsecrets.yaml new file mode 100644 index 000000000..87c4e63bc --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/crds/dbsecrets.yaml @@ -0,0 +1,85 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + "helm.sh/hook": crd-install + "helm.sh/hook-delete-policy": "before-hook-creation" + creationTimestamp: null + name: dbsecrets.digitalis.io +spec: + group: digitalis.io + names: + kind: DbSecret + listKind: DbSecretList + plural: dbsecrets + singular: dbsecret + scope: Namespaced + versions: + - name: v1beta1 + schema: + openAPIV3Schema: + description: DbSecret is the Schema for the dbsecrets API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DbSecretSpec defines the desired state of DbSecret + properties: + renew: + type: boolean + rollout: + items: + properties: + kind: + description: Kind is either Deployment, Pod or StatefulSet + type: string + name: + description: Name is the object name + type: string + required: + - kind + - name + type: object + type: array + secretName: + description: Name can override the secret name, defaults to manifests.name + type: string + template: + additionalProperties: + type: string + type: object + vault: + properties: + mount: + description: Mount is the vault database + type: string + role: + description: Role is the vault role used to connect to the database + type: string + required: + - mount + - role + type: object + required: + - vault + type: object + status: + description: DbSecretStatus defines the observed state of DbSecret + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/digitalis/vals-operator/0.7.10/crds/valssecrets.yaml b/charts/digitalis/vals-operator/0.7.10/crds/valssecrets.yaml new file mode 100644 index 000000000..28b224994 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/crds/valssecrets.yaml @@ -0,0 +1,134 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + "helm.sh/hook": crd-install + "helm.sh/hook-delete-policy": "before-hook-creation" + creationTimestamp: null + name: valssecrets.digitalis.io +spec: + group: digitalis.io + names: + kind: ValsSecret + listKind: ValsSecretList + plural: valssecrets + singular: valssecret + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: ValsSecret is the Schema for the valssecrets API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ValsSecretSpec defines the desired state of ValsSecret + properties: + data: + additionalProperties: + properties: + encoding: + description: Encoding type for the secret. Only base64 supported. + Optional + type: string + ref: + description: Ref value to the secret in the format ref+backend://path + https://github.com/helmfile/vals + type: string + required: + - ref + type: object + type: object + databases: + items: + properties: + driver: + description: Defines the database type + type: string + hosts: + description: List of hosts to connect to, they'll be tried in + sequence until one succeeds + items: + type: string + type: array + loginCredentials: + description: Credentials to access the database + properties: + namespace: + description: Optional namespace of the secret, default current + namespace + type: string + passwordKey: + description: Key in the secret containing the database username + type: string + secretName: + description: Name of the secret containing the credentials + to be able to log in to the database + type: string + usernameKey: + description: Key in the secret containing the database username + type: string + required: + - passwordKey + - secretName + type: object + passwordKey: + description: Key in the secret containing the database username + type: string + port: + description: Database port number + type: integer + userHost: + description: Used for MySQL only, the host part for the username + type: string + usernameKey: + description: Key in the secret containing the database username + type: string + required: + - driver + - hosts + - passwordKey + type: object + type: array + name: + type: string + template: + type: object + additionalProperties: + type: string + ttl: + format: int64 + type: integer + type: + type: string + required: + - data + type: object + status: + description: ValsSecretStatus defines the observed state of ValsSecret + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/charts/digitalis/vals-operator/0.7.10/questions.yaml b/charts/digitalis/vals-operator/0.7.10/questions.yaml new file mode 100644 index 000000000..7976cff0c --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/questions.yaml @@ -0,0 +1,26 @@ +questions: +#image configurations +- variable: image.repository + default: "digitalisdocker/vals-operator" + description: image registry + type: string + label: Image Registry + group: "Container Images" +- variable: image.tag + default: "v0.3.0" + description: Image tag + type: string + label: Image Tag + group: "Container Images" +- variable: imagePullSecrets + default: "" + description: secret name to pull image + type: string + label: Image Pull Secrets + group: "Container Images" +- variable: environmentSecret + default: "" + description: "The secret containing env variables to access the backend secrets store." + label: Config Secret + type: string + group: "Settings" diff --git a/charts/digitalis/vals-operator/0.7.10/templates/NOTES.txt b/charts/digitalis/vals-operator/0.7.10/templates/NOTES.txt new file mode 100644 index 000000000..e69de29bb diff --git a/charts/digitalis/vals-operator/0.7.10/templates/_helpers.tpl b/charts/digitalis/vals-operator/0.7.10/templates/_helpers.tpl new file mode 100644 index 000000000..dcd31f04a --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "vals-operator.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 "vals-operator.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 "vals-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "vals-operator.labels" -}} +helm.sh/chart: {{ include "vals-operator.chart" . }} +{{ include "vals-operator.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "vals-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "vals-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "vals-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "vals-operator.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/digitalis/vals-operator/0.7.10/templates/crds.yaml b/charts/digitalis/vals-operator/0.7.10/templates/crds.yaml new file mode 100644 index 000000000..baaa6e892 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/templates/crds.yaml @@ -0,0 +1,7 @@ +{{- if .Values.manageCrds -}} +{{ $.Files.Get "crds/valssecrets.yaml" }} +{{- if .Values.enableDbSecrets -}} +--- +{{ $.Files.Get "crds/dbsecrets.yaml" }} +{{- end }} +{{- end }} diff --git a/charts/digitalis/vals-operator/0.7.10/templates/deployment.yaml b/charts/digitalis/vals-operator/0.7.10/templates/deployment.yaml new file mode 100644 index 000000000..a8ec5d211 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/templates/deployment.yaml @@ -0,0 +1,75 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "vals-operator.fullname" . }} + labels: + {{- include "vals-operator.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- include "vals-operator.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "vals-operator.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "vals-operator.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 }} + {{- if .Values.args }} + args: + {{- toYaml .Values.args | nindent 12 }} + {{- end }} + {{- if .Values.environmentSecret }} + envFrom: + - secretRef: + name: "{{ .Values.environmentSecret }}" + {{- else }} + envFrom: + {{- toYaml .Values.secretEnv | nindent 12 }} + {{- end }} + {{- if .Values.env }} + env: + {{- toYaml .Values.env | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- if .Values.volumeMounts }} + volumeMounts: + {{- toYaml .Values.volumeMounts | nindent 12 }} + {{- end }} + ports: + - containerPort: {{ .Values.metricsPort | default 8080 }} + name: metrics + protocol: TCP + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.volumes }} + volumes: + {{- toYaml .Values.volumes | nindent 8 }} + {{- end }} diff --git a/charts/digitalis/vals-operator/0.7.10/templates/podmonitor.yaml b/charts/digitalis/vals-operator/0.7.10/templates/podmonitor.yaml new file mode 100644 index 000000000..f3db4e6e0 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/templates/podmonitor.yaml @@ -0,0 +1,20 @@ +{{- if .Values.podMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: {{ include "vals-operator.fullname" . }} + labels: + {{- include "vals-operator.labels" . | nindent 4 }} +spec: + podMetricsEndpoints: + - interval: 30s + port: "metrics" + path: "/metrics" + namespaceSelector: + matchNames: + - "{{ .Release.Namespace }}" + selector: + matchLabels: + app.kubernetes.io/name: {{ include "vals-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/digitalis/vals-operator/0.7.10/templates/prometheusrules.yaml b/charts/digitalis/vals-operator/0.7.10/templates/prometheusrules.yaml new file mode 100644 index 000000000..cb4515852 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/templates/prometheusrules.yaml @@ -0,0 +1,68 @@ +{{- if .Values.prometheusRules.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "vals-operator.fullname" . }} + labels: + {{- include "vals-operator.labels" . | nindent 4 }} +spec: + groups: + - name: vals-operator + rules: +{{- if .Values.enableDbSecrets }} + - alert: ValsOperatorDbSecretError + expr: vals_operator_dbsecret_error > time() - 300 + for: 30m + labels: + severity: warning + {{- if .Values.prometheusRules.additionalRuleLabels }} + {{- with .Values.prometheusRules.additionalRuleLabels }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + annotations: + summary: vals-operator database secret not issued + description: "Vals operator has been unable to issue database credentials for secret {{`{{`}}$labels.secret{{`}}`}} in namespace {{`{{`}}$labels.namespace{{`}}`}}" + {{- if .Values.prometheusRules.additionalRuleAnnotations }} + {{- with .Values.prometheusRules.additionalRuleAnnotations }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + - alert: ValsOperatorDbSecretExpired + expr: time() > vals_operator_dbsecret_expire_time + for: 30m + labels: + severity: warning + {{- if .Values.prometheusRules.additionalRuleLabels }} + {{- with .Values.prometheusRules.additionalRuleLabels }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + annotations: + summary: vals-operator database secret expired + description: "Vals operator database credentials for secret {{`{{`}}$labels.secret{{`}}`}} in namespace {{`{{`}}$labels.namespace{{`}}`}} expired" + {{- if .Values.prometheusRules.additionalRuleAnnotations }} + {{- with .Values.prometheusRules.additionalRuleAnnotations }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} +{{- end }} + - alert: ValsOperatorSecretError + expr: vals_operator_secret_error > time() - 300 + for: 30m + labels: + severity: warning + {{- if .Values.prometheusRules.additionalRuleLabels }} + {{- with .Values.prometheusRules.additionalRuleLabels }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + annotations: + summary: vals-operator secret not issued + description: "Vals operator has been unable to create the secret for {{`{{`}}$labels.secret{{`}}`}} in namespace {{`{{`}}$labels.namespace{{`}}`}}" + {{- if .Values.prometheusRules.additionalRuleAnnotations }} + {{- with .Values.prometheusRules.additionalRuleAnnotations }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/digitalis/vals-operator/0.7.10/templates/serviceaccount.yaml b/charts/digitalis/vals-operator/0.7.10/templates/serviceaccount.yaml new file mode 100644 index 000000000..6d225fcf6 --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/templates/serviceaccount.yaml @@ -0,0 +1,91 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: vals-operator + labels: + {{- include "vals-operator.labels" . | nindent 4 }} +rules: + {{- if .Values.enableDbSecrets }} +- apiGroups: + - "apps" + resources: + - "statefulsets" + - "deployments" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "delete" + - "create" + {{- end }} +- apiGroups: + - "" + resources: + - "secrets" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "delete" + - "create" +- apiGroups: + - "" + resources: + - "events" + verbs: + - "create" + - "patch" +- apiGroups: + - "digitalis.io" + resources: + - "valssecrets" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "delete" + - "create" +{{- if .Values.enableDbSecrets }} +- apiGroups: + - "digitalis.io" + resources: + - "dbsecrets" + verbs: + - "get" + - "list" + - "watch" + - "update" + - "delete" + - "create" +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: vals-operator + labels: + {{- include "vals-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: vals-operator +subjects: + - kind: ServiceAccount + name: {{ include "vals-operator.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "vals-operator.serviceAccountName" . }} + labels: + {{- include "vals-operator.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/digitalis/vals-operator/0.7.10/values.yaml b/charts/digitalis/vals-operator/0.7.10/values.yaml new file mode 100644 index 000000000..11bcb6aea --- /dev/null +++ b/charts/digitalis/vals-operator/0.7.10/values.yaml @@ -0,0 +1,117 @@ +replicaCount: 1 + +image: + repository: ghcr.io/digitalis-io/vals-operator + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +manageCrds: true + +# This may not be required by everyone and the pod will require wider permissions +# which may not be desired on secure environments +enableDbSecrets: true + +prometheusRules: + enabled: false + ## Additional labels for PrometheusRule alerts + additionalRuleLabels: {} + + ## Additional annotations for PrometheusRule alerts + additionalRuleAnnotations: {} + +# additional arguments to operator +args: [] + # -exclude-namespaces string + # Comma separated list of namespaces to ignore. + # -health-probe-bind-address string + # The address the probe endpoint binds to. (default ":8081") + # -kubeconfig string + # Paths to a kubeconfig. Only required if out-of-cluster. + # -leader-elect + # Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager. + # -metrics-bind-address string + # The address the metric endpoint binds to. (default ":8080") + # -reconcile-period duration + # How often the controller will re-queue vals-operator events. (default 5s) + # -record-changes + # Records every time a secret has been updated. You can view them with kubectl describe. It may also be disabled globally and enabled per secret via the annotation 'vals-operator.digitalis.io/record: "true"' (default true) + # -ttl duration + # How often to check backend for updates. (default 5m0s) + # -watch-namespaces string + # Comma separated list of namespaces that vals-operator will watch. + # -zap-devel + # Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn). Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) (default true) + # -zap-encoder value + # Zap log encoding (one of 'json' or 'console') + # -zap-log-level value + # Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error', or any integer value > 0 which corresponds to custom debug levels of increasing verbosity + # -zap-stacktrace-level value + # Zap Level at and above which stacktraces are captured (one of 'info', 'error', 'panic'). + + +environmentSecret: "" + +# See https://github.com/helmfile/vals +# for information on setting up your backend environment. +env: [] + # - name: VAULT_SKIP_VERIFY + # value: "true" + +secretEnv: [] + # - secretRef: + # name: aws-creds + +volumes: [] + # - name: creds + # secret: + # secretName: gcs-credentials +volumeMounts: [] + # - name: creds + # mountPath: /secret + # readOnly: true + + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +podMonitor: + # When set to true then use a podMonitor to collect metrics + enabled: false + # Custom labels to use in the podMonitor to be matched with a specific Prometheus + labels: {} + # Set the namespace the podMonitor should be deployed to + # namespace: default + # Set how frequently Prometheus should scrape + # interval: 30s + # Set timeout for scrape + # scrapeTimeout: 10s + +resources: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/charts/kuma/kuma/2.8.2/.helmdocsignore b/charts/kuma/kuma/2.8.2/.helmdocsignore new file mode 100644 index 000000000..d8a5db8f8 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/.helmdocsignore @@ -0,0 +1 @@ +# Charts to ignore from helm-docs \ No newline at end of file diff --git a/charts/kuma/kuma/2.8.2/.helmignore b/charts/kuma/kuma/2.8.2/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/kuma/kuma/2.8.2/Chart.yaml b/charts/kuma/kuma/2.8.2/Chart.yaml new file mode 100644 index 000000000..b4424181e --- /dev/null +++ b/charts/kuma/kuma/2.8.2/Chart.yaml @@ -0,0 +1,26 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Kuma + catalog.cattle.io/namespace: kuma-system + catalog.cattle.io/release-name: kuma +apiVersion: v2 +appVersion: 2.8.2 +description: A Helm chart for the Kuma Control Plane +home: https://github.com/kumahq/kuma +icon: file://assets/icons/kuma.svg +keywords: +- service mesh +- control plane +maintainers: +- email: jakub.dyszkiewicz@konghq.com + name: Jakub Dyszkiewicz + url: https://github.com/jakubdyszkiewicz +- email: charly.molter@konghq.com + name: Charly Molter + url: https://github.com/lahabana +- email: michael.beaumont@konghq.com + name: Mike Beaumont + url: https://github.com/michaelbeaumont +name: kuma +type: application +version: 2.8.2 diff --git a/charts/kuma/kuma/2.8.2/README.md b/charts/kuma/kuma/2.8.2/README.md new file mode 100644 index 000000000..d83119e96 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/README.md @@ -0,0 +1,256 @@ +[![][kuma-logo]][kuma-url] + +A Helm chart for the Kuma Control Plane + +![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![Version: 2.8.2](https://img.shields.io/badge/Version-2.8.2-informational?style=flat-square) ![AppVersion: 2.8.2](https://img.shields.io/badge/AppVersion-2.8.2-informational?style=flat-square) + +**Homepage:** + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| global.image.registry | string | `"docker.io/kumahq"` | Default registry for all Kuma Images | +| global.image.tag | string | `nil` | The default tag for all Kuma images, which itself defaults to .Chart.AppVersion | +| global.imagePullSecrets | list | `[]` | Add `imagePullSecrets` to all the service accounts used for Kuma components | +| patchSystemNamespace | bool | `true` | Whether to patch the target namespace with the system label | +| installCrdsOnUpgrade.enabled | bool | `true` | Whether install new CRDs before upgrade (if any were introduced with the new version of Kuma) | +| installCrdsOnUpgrade.imagePullSecrets | list | `[]` | The `imagePullSecrets` to attach to the Service Account running CRD installation. This field will be deprecated in a future release, please use .global.imagePullSecrets | +| noHelmHooks | bool | `false` | Whether to disable all helm hooks | +| restartOnSecretChange | bool | `true` | Whether to restart control-plane by calculating a new checksum for the secret | +| controlPlane.environment | string | `"kubernetes"` | Environment that control plane is run in, useful when running universal global control plane on k8s | +| controlPlane.extraLabels | object | `{}` | Labels to add to resources in addition to default labels | +| controlPlane.logLevel | string | `"info"` | Kuma CP log level: one of off,info,debug | +| controlPlane.logOutputPath | string | `""` | Kuma CP log output path: Defaults to /dev/stdout | +| controlPlane.mode | string | `"zone"` | Kuma CP modes: one of zone,global | +| controlPlane.zone | string | `nil` | Kuma CP zone, if running multizone | +| controlPlane.kdsGlobalAddress | string | `""` | Only used in `zone` mode | +| controlPlane.replicas | int | `1` | Number of replicas of the Kuma CP. Ignored when autoscaling is enabled | +| controlPlane.minReadySeconds | int | `0` | Minimum number of seconds for which a newly created pod should be ready for it to be considered available. | +| controlPlane.deploymentAnnotations | object | `{}` | Annotations applied only to the `Deployment` resource | +| controlPlane.podAnnotations | object | `{}` | Annotations applied only to the `Pod` resource | +| controlPlane.autoscaling.enabled | bool | `false` | Whether to enable Horizontal Pod Autoscaling, which requires the [Metrics Server](https://github.com/kubernetes-sigs/metrics-server) in the cluster | +| controlPlane.autoscaling.minReplicas | int | `2` | The minimum CP pods to allow | +| controlPlane.autoscaling.maxReplicas | int | `5` | The max CP pods to scale to | +| controlPlane.autoscaling.targetCPUUtilizationPercentage | int | `80` | For clusters that don't support autoscaling/v2, autoscaling/v1 is used | +| controlPlane.autoscaling.metrics | list | `[{"resource":{"name":"cpu","target":{"averageUtilization":80,"type":"Utilization"}},"type":"Resource"}]` | For clusters that do support autoscaling/v2, use metrics | +| controlPlane.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for the Kuma Control Plane pods | +| controlPlane.tolerations | list | `[]` | Tolerations for the Kuma Control Plane pods | +| controlPlane.podDisruptionBudget.enabled | bool | `false` | Whether to create a pod disruption budget | +| controlPlane.podDisruptionBudget.maxUnavailable | int | `1` | The maximum number of unavailable pods allowed by the budget | +| controlPlane.affinity | object | `{"podAntiAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"In","values":["{{ include \"kuma.name\" . }}"]},{"key":"app.kubernetes.io/instance","operator":"In","values":["{{ .Release.Name }}"]},{"key":"app","operator":"In","values":["{{ include \"kuma.name\" . }}-control-plane"]}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]}}` | Affinity placement rule for the Kuma Control Plane pods. This is rendered as a template, so you can reference other helm variables or includes. | +| controlPlane.topologySpreadConstraints | string | `nil` | Topology spread constraints rule for the Kuma Control Plane pods. This is rendered as a template, so you can use variables to generate match labels. | +| controlPlane.injectorFailurePolicy | string | `"Fail"` | Failure policy of the mutating webhook implemented by the Kuma Injector component | +| controlPlane.service.apiServer.http.nodePort | int | `30681` | Port on which Http api server Service is exposed on Node for service of type NodePort | +| controlPlane.service.apiServer.https.nodePort | int | `30682` | Port on which Https api server Service is exposed on Node for service of type NodePort | +| controlPlane.service.enabled | bool | `true` | Whether to create a service resource. | +| controlPlane.service.name | string | `nil` | Optionally override of the Kuma Control Plane Service's name | +| controlPlane.service.type | string | `"ClusterIP"` | Service type of the Kuma Control Plane | +| controlPlane.service.annotations | object | `{"prometheus.io/port":"5680","prometheus.io/scrape":"true"}` | Annotations to put on the Kuma Control Plane | +| controlPlane.ingress.enabled | bool | `false` | Install K8s Ingress resource that exposes GUI and API | +| controlPlane.ingress.ingressClassName | string | `nil` | IngressClass defines which controller will implement the resource | +| controlPlane.ingress.hostname | string | `nil` | Ingress hostname | +| controlPlane.ingress.annotations | object | `{}` | Map of ingress annotations. | +| controlPlane.ingress.path | string | `"/"` | Ingress path. | +| controlPlane.ingress.pathType | string | `"ImplementationSpecific"` | Each path in an Ingress is required to have a corresponding path type. (ImplementationSpecific/Exact/Prefix) | +| controlPlane.ingress.servicePort | int | `5681` | Port from kuma-cp to use to expose API and GUI. Switch to 5682 to expose TLS port | +| controlPlane.globalZoneSyncService.enabled | bool | `true` | Whether to create a k8s service for the global zone sync service. It will only be created when enabled and deploying the global control plane. | +| controlPlane.globalZoneSyncService.type | string | `"LoadBalancer"` | Service type of the Global-zone sync | +| controlPlane.globalZoneSyncService.loadBalancerIP | string | `nil` | Optionally specify IP to be used by cloud provider when configuring load balancer | +| controlPlane.globalZoneSyncService.loadBalancerSourceRanges | list | `[]` | Optionally specify allowed source ranges that can access the load balancer | +| controlPlane.globalZoneSyncService.annotations | object | `{}` | Additional annotations to put on the Global Zone Sync Service | +| controlPlane.globalZoneSyncService.nodePort | int | `30685` | Port on which Global Zone Sync Service is exposed on Node for service of type NodePort | +| controlPlane.globalZoneSyncService.port | int | `5685` | Port on which Global Zone Sync Service is exposed | +| controlPlane.globalZoneSyncService.protocol | string | `"grpc"` | Protocol of the Global Zone Sync service port | +| controlPlane.defaults.skipMeshCreation | bool | `false` | Whether to skip creating the default Mesh | +| controlPlane.automountServiceAccountToken | bool | `true` | Whether to automountServiceAccountToken for cp. Optionally set to false | +| controlPlane.resources | object | `{"limits":{"memory":"256Mi"},"requests":{"cpu":"500m","memory":"256Mi"}}` | Optionally override the resource spec | +| controlPlane.lifecycle | object | `{}` | Pod lifecycle settings (useful for adding a preStop hook, when using AWS ALB or NLB) | +| controlPlane.terminationGracePeriodSeconds | int | `30` | Number of seconds to wait before force killing the pod. Make sure to update this if you add a preStop hook. | +| controlPlane.tls.general.secretName | string | `""` | Secret that contains tls.crt, tls.key [and ca.crt when no controlPlane.tls.general.caSecretName specified] for protecting Kuma in-cluster communication | +| controlPlane.tls.general.caSecretName | string | `""` | Secret that contains ca.crt that was used to sign cert for protecting Kuma in-cluster communication (ca.crt present in this secret have precedence over the one provided in the controlPlane.tls.general.secretName) | +| controlPlane.tls.general.caBundle | string | `""` | Base64 encoded CA certificate (the same as in controlPlane.tls.general.secret#ca.crt) | +| controlPlane.tls.apiServer.secretName | string | `""` | Secret that contains tls.crt, tls.key for protecting Kuma API on HTTPS | +| controlPlane.tls.apiServer.clientCertsSecretName | string | `""` | Secret that contains list of .pem certificates that can access admin endpoints of Kuma API on HTTPS | +| controlPlane.tls.kdsGlobalServer.secretName | string | `""` | Name of the K8s TLS Secret resource. If you set this and don't set create=true, you have to create the secret manually. | +| controlPlane.tls.kdsGlobalServer.create | bool | `false` | Whether to create the TLS secret in helm. | +| controlPlane.tls.kdsGlobalServer.cert | string | `""` | The TLS certificate to offer. | +| controlPlane.tls.kdsGlobalServer.key | string | `""` | The TLS key to use. | +| controlPlane.tls.kdsZoneClient.secretName | string | `""` | Name of the K8s Secret resource that contains ca.crt which was used to sign the certificate of KDS Global Server. If you set this and don't set create=true, you have to create the secret manually. | +| controlPlane.tls.kdsZoneClient.create | bool | `false` | Whether to create the TLS secret in helm. | +| controlPlane.tls.kdsZoneClient.cert | string | `""` | CA bundle that was used to sign the certificate of KDS Global Server. | +| controlPlane.tls.kdsZoneClient.skipVerify | bool | `false` | If true, TLS cert of the server is not verified. | +| controlPlane.serviceAccountAnnotations | object | `{}` | Annotations to add for Control Plane's Service Account | +| controlPlane.image.pullPolicy | string | `"IfNotPresent"` | Kuma CP ImagePullPolicy | +| controlPlane.image.repository | string | `"kuma-cp"` | Kuma CP image repository | +| controlPlane.image.tag | string | `nil` | Kuma CP Image tag. When not specified, the value is copied from global.tag | +| controlPlane.secrets | object with { Env: string, Secret: string, Key: string } | `nil` | Secrets to add as environment variables, where `Env` is the name of the env variable, `Secret` is the name of the Secret, and `Key` is the key of the Secret value to use | +| controlPlane.envVars | object | `{}` | Additional environment variables that will be passed to the control plane | +| controlPlane.extraConfigMaps | list | `[]` | Additional config maps to mount into the control plane, with optional inline values | +| controlPlane.extraSecrets | object with { name: string, mountPath: string, readOnly: string } | `nil` | Additional secrets to mount into the control plane, where `Env` is the name of the env variable, `Secret` is the name of the Secret, and `Key` is the key of the Secret value to use | +| controlPlane.webhooks.validator.additionalRules | string | `""` | Additional rules to apply on Kuma validator webhook. Useful when building custom policy on top of Kuma. | +| controlPlane.webhooks.ownerReference.additionalRules | string | `""` | Additional rules to apply on Kuma owner reference webhook. Useful when building custom policy on top of Kuma. | +| controlPlane.hostNetwork | bool | `false` | Specifies if the deployment should be started in hostNetwork mode. | +| controlPlane.admissionServerPort | int | `5443` | Define a new server port for the admission controller. Recommended to set in combination with hostNetwork to prevent multiple port bindings on the same port (like Calico in AWS EKS). | +| controlPlane.podSecurityContext | object | `{"runAsNonRoot":true}` | Security context at the pod level for control plane. | +| controlPlane.containerSecurityContext | object | `{"readOnlyRootFilesystem":true}` | Security context at the container level for control plane. | +| controlPlane.supportGatewaySecretsInAllNamespaces | bool | `false` | If true, then control plane can support TLS secrets for builtin gateway outside of mesh system namespace. The downside is that control plane requires permission to read Secrets in all namespaces. | +| cni.enabled | bool | `false` | Install Kuma with CNI instead of proxy init container | +| cni.chained | bool | `false` | Install CNI in chained mode | +| cni.netDir | string | `"/etc/cni/multus/net.d"` | Set the CNI install directory | +| cni.binDir | string | `"/var/lib/cni/bin"` | Set the CNI bin directory | +| cni.confName | string | `"kuma-cni.conf"` | Set the CNI configuration name | +| cni.logLevel | string | `"info"` | CNI log level: one of off,info,debug | +| cni.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node Selector for the CNI pods | +| cni.tolerations | list | `[]` | Tolerations for the CNI pods | +| cni.podAnnotations | object | `{}` | Additional pod annotations | +| cni.namespace | string | `"kube-system"` | Set the CNI namespace | +| cni.image.repository | string | `"kuma-cni"` | CNI image repository | +| cni.image.tag | string | `nil` | CNI image tag - defaults to .Chart.AppVersion | +| cni.image.imagePullPolicy | string | `"IfNotPresent"` | CNI image pull policy | +| cni.delayStartupSeconds | int | `0` | it's only useful in tests to trigger a possible race condition | +| cni.experimental | object | `{"imageEbpf":{"registry":"docker.io/kumahq","repository":"merbridge","tag":"0.8.5"}}` | use new CNI (experimental) | +| cni.experimental.imageEbpf.registry | string | `"docker.io/kumahq"` | CNI experimental eBPF image registry | +| cni.experimental.imageEbpf.repository | string | `"merbridge"` | CNI experimental eBPF image repository | +| cni.experimental.imageEbpf.tag | string | `"0.8.5"` | CNI experimental eBPF image tag | +| cni.resources.requests.cpu | string | `"100m"` | | +| cni.resources.requests.memory | string | `"100Mi"` | | +| cni.resources.limits.memory | string | `"100Mi"` | | +| cni.podSecurityContext | object | `{}` | Security context at the pod level for cni | +| cni.containerSecurityContext | object | `{"readOnlyRootFilesystem":true,"runAsGroup":0,"runAsNonRoot":false,"runAsUser":0}` | Security context at the container level for cni | +| dataPlane.dnsLogging | bool | `false` | If true, then turn on CoreDNS query logging | +| dataPlane.image.repository | string | `"kuma-dp"` | The Kuma DP image repository | +| dataPlane.image.pullPolicy | string | `"IfNotPresent"` | Kuma DP ImagePullPolicy | +| dataPlane.image.tag | string | `nil` | Kuma DP Image Tag. When not specified, the value is copied from global.tag | +| dataPlane.initImage.repository | string | `"kuma-init"` | The Kuma DP init image repository | +| dataPlane.initImage.tag | string | `nil` | Kuma DP init image tag When not specified, the value is copied from global.tag | +| ingress.enabled | bool | `false` | If true, it deploys Ingress for cross cluster communication | +| ingress.extraLabels | object | `{}` | Labels to add to resources, in addition to default labels | +| ingress.drainTime | string | `"30s"` | Time for which old listener will still be active as draining | +| ingress.replicas | int | `1` | Number of replicas of the Ingress. Ignored when autoscaling is enabled. | +| ingress.logLevel | string | `"info"` | Log level for ingress (available values: off|info|debug) | +| ingress.resources | object | `{"limits":{"cpu":"1000m","memory":"512Mi"},"requests":{"cpu":"50m","memory":"64Mi"}}` | Define the resources to allocate to mesh ingress | +| ingress.lifecycle | object | `{}` | Pod lifecycle settings (useful for adding a preStop hook, when using AWS ALB or NLB) | +| ingress.terminationGracePeriodSeconds | int | `40` | Number of seconds to wait before force killing the pod. Make sure to update this if you add a preStop hook. | +| ingress.autoscaling.enabled | bool | `false` | Whether to enable Horizontal Pod Autoscaling, which requires the [Metrics Server](https://github.com/kubernetes-sigs/metrics-server) in the cluster | +| ingress.autoscaling.minReplicas | int | `2` | The minimum CP pods to allow | +| ingress.autoscaling.maxReplicas | int | `5` | The max CP pods to scale to | +| ingress.autoscaling.targetCPUUtilizationPercentage | int | `80` | For clusters that don't support autoscaling/v2, autoscaling/v1 is used | +| ingress.autoscaling.metrics | list | `[{"resource":{"name":"cpu","target":{"averageUtilization":80,"type":"Utilization"}},"type":"Resource"}]` | For clusters that do support autoscaling/v2, use metrics | +| ingress.service.enabled | bool | `true` | Whether to create a Service resource. | +| ingress.service.type | string | `"LoadBalancer"` | Service type of the Ingress | +| ingress.service.loadBalancerIP | string | `nil` | Optionally specify IP to be used by cloud provider when configuring load balancer | +| ingress.service.annotations | object | `{}` | Additional annotations to put on the Ingress service | +| ingress.service.port | int | `10001` | Port on which Ingress is exposed | +| ingress.service.nodePort | string | `nil` | Port on which service is exposed on Node for service of type NodePort | +| ingress.annotations | object | `{}` | Additional pod annotations (deprecated favor `podAnnotations`) | +| ingress.podAnnotations | object | `{}` | Additional pod annotations | +| ingress.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node Selector for the Ingress pods | +| ingress.tolerations | list | `[]` | Tolerations for the Ingress pods | +| ingress.podDisruptionBudget.enabled | bool | `false` | Whether to create a pod disruption budget | +| ingress.podDisruptionBudget.maxUnavailable | int | `1` | The maximum number of unavailable pods allowed by the budget | +| ingress.affinity | object | `{"podAntiAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"In","values":["{{ include \"kuma.name\" . }}"]},{"key":"app.kubernetes.io/instance","operator":"In","values":["{{ .Release.Name }}"]},{"key":"app","operator":"In","values":["kuma-ingress"]}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]}}` | Affinity placement rule for the Kuma Ingress pods This is rendered as a template, so you can reference other helm variables or includes. | +| ingress.topologySpreadConstraints | string | `nil` | Topology spread constraints rule for the Kuma Mesh Ingress pods. This is rendered as a template, so you can use variables to generate match labels. | +| ingress.podSecurityContext | object | `{"runAsGroup":5678,"runAsNonRoot":true,"runAsUser":5678}` | Security context at the pod level for ingress | +| ingress.containerSecurityContext | object | `{"readOnlyRootFilesystem":true}` | Security context at the container level for ingress | +| ingress.serviceAccountAnnotations | object | `{}` | Annotations to add for Control Plane's Service Account | +| ingress.automountServiceAccountToken | bool | `true` | Whether to automountServiceAccountToken for cp. Optionally set to false | +| egress.enabled | bool | `false` | If true, it deploys Egress for cross cluster communication | +| egress.extraLabels | object | `{}` | Labels to add to resources, in addition to the default labels. | +| egress.drainTime | string | `"30s"` | Time for which old listener will still be active as draining | +| egress.replicas | int | `1` | Number of replicas of the Egress. Ignored when autoscaling is enabled. | +| egress.logLevel | string | `"info"` | Log level for egress (available values: off|info|debug) | +| egress.autoscaling.enabled | bool | `false` | Whether to enable Horizontal Pod Autoscaling, which requires the [Metrics Server](https://github.com/kubernetes-sigs/metrics-server) in the cluster | +| egress.autoscaling.minReplicas | int | `2` | The minimum CP pods to allow | +| egress.autoscaling.maxReplicas | int | `5` | The max CP pods to scale to | +| egress.autoscaling.targetCPUUtilizationPercentage | int | `80` | For clusters that don't support autoscaling/v2, autoscaling/v1 is used | +| egress.autoscaling.metrics | list | `[{"resource":{"name":"cpu","target":{"averageUtilization":80,"type":"Utilization"}},"type":"Resource"}]` | For clusters that do support autoscaling/v2, use metrics | +| egress.resources.requests.cpu | string | `"50m"` | | +| egress.resources.requests.memory | string | `"64Mi"` | | +| egress.resources.limits.cpu | string | `"1000m"` | | +| egress.resources.limits.memory | string | `"512Mi"` | | +| egress.service.enabled | bool | `true` | Whether to create the service object | +| egress.service.type | string | `"ClusterIP"` | Service type of the Egress | +| egress.service.loadBalancerIP | string | `nil` | Optionally specify IP to be used by cloud provider when configuring load balancer | +| egress.service.annotations | object | `{}` | Additional annotations to put on the Egress service | +| egress.service.port | int | `10002` | Port on which Egress is exposed | +| egress.service.nodePort | string | `nil` | Port on which service is exposed on Node for service of type NodePort | +| egress.annotations | object | `{}` | Additional pod annotations (deprecated favor `podAnnotations`) | +| egress.podAnnotations | object | `{}` | Additional pod annotations | +| egress.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node Selector for the Egress pods | +| egress.tolerations | list | `[]` | Tolerations for the Egress pods | +| egress.podDisruptionBudget.enabled | bool | `false` | Whether to create a pod disruption budget | +| egress.podDisruptionBudget.maxUnavailable | int | `1` | The maximum number of unavailable pods allowed by the budget | +| egress.affinity | object | `{"podAntiAffinity":{"preferredDuringSchedulingIgnoredDuringExecution":[{"podAffinityTerm":{"labelSelector":{"matchExpressions":[{"key":"app.kubernetes.io/name","operator":"In","values":["{{ include \"kuma.name\" . }}"]},{"key":"app.kubernetes.io/instance","operator":"In","values":["{{ .Release.Name }}"]},{"key":"app","operator":"In","values":["kuma-egress"]}]},"topologyKey":"kubernetes.io/hostname"},"weight":100}]}}` | Affinity placement rule for the Kuma Egress pods. This is rendered as a template, so you can reference other helm variables or includes. | +| egress.topologySpreadConstraints | string | `nil` | Topology spread constraints rule for the Kuma Egress pods. This is rendered as a template, so you can use variables to generate match labels. | +| egress.podSecurityContext | object | `{"runAsGroup":5678,"runAsNonRoot":true,"runAsUser":5678}` | Security context at the pod level for egress | +| egress.containerSecurityContext | object | `{"readOnlyRootFilesystem":true}` | Security context at the container level for egress | +| egress.serviceAccountAnnotations | object | `{}` | Annotations to add for Control Plane's Service Account | +| egress.automountServiceAccountToken | bool | `true` | Whether to automountServiceAccountToken for cp. Optionally set to false | +| kumactl.image.repository | string | `"kumactl"` | The kumactl image repository | +| kumactl.image.tag | string | `nil` | The kumactl image tag. When not specified, the value is copied from global.tag | +| kubectl.image.registry | string | `"docker.io"` | The kubectl image registry | +| kubectl.image.repository | string | `"bitnami/kubectl"` | The kubectl image repository | +| kubectl.image.tag | string | `"1.27.5"` | The kubectl image tag | +| hooks.nodeSelector | object | `{"kubernetes.io/os":"linux"}` | Node selector for the HELM hooks | +| hooks.tolerations | list | `[]` | Tolerations for the HELM hooks | +| hooks.podSecurityContext | object | `{"runAsNonRoot":true}` | Security context at the pod level for crd/webhook/ns | +| hooks.containerSecurityContext | object | `{"readOnlyRootFilesystem":true}` | Security context at the container level for crd/webhook/ns | +| hooks.ebpfCleanup | object | `{"containerSecurityContext":{"readOnlyRootFilesystem":false},"podSecurityContext":{"runAsNonRoot":false}}` | ebpf-cleanup hook needs write access to the root filesystem to clean ebpf programs Changing below values will potentially break ebpf cleanup completely, so be cautious when doing so. | +| hooks.ebpfCleanup.podSecurityContext | object | `{"runAsNonRoot":false}` | Security context at the pod level for crd/webhook/cleanup-ebpf | +| hooks.ebpfCleanup.containerSecurityContext | object | `{"readOnlyRootFilesystem":false}` | Security context at the container level for crd/webhook/cleanup-ebpf | +| experimental.ebpf.enabled | bool | `false` | If true, ebpf will be used instead of using iptables to install/configure transparent proxy | +| experimental.ebpf.instanceIPEnvVarName | string | `"INSTANCE_IP"` | Name of the environmental variable which will contain the IP address of a pod | +| experimental.ebpf.bpffsPath | string | `"/sys/fs/bpf"` | Path where BPF file system should be mounted | +| experimental.ebpf.cgroupPath | string | `"/sys/fs/cgroup"` | Host's cgroup2 path | +| experimental.ebpf.tcAttachIface | string | `""` | Name of the network interface which TC programs should be attached to, we'll try to automatically determine it if empty | +| experimental.ebpf.programsSourcePath | string | `"/tmp/kuma-ebpf"` | Path where compiled eBPF programs which will be installed can be found | +| experimental.deltaKds | bool | `true` | If false, it uses legacy API for resource synchronization | +| experimental.sidecarContainers | bool | `false` | If true, enable native Kubernetes sidecars. This requires at least Kubernetes v1.29 | +| postgres.port | string | `"5432"` | Postgres port, password should be provided as a secret reference in "controlPlane.secrets" with the Env value "KUMA_STORE_POSTGRES_PASSWORD". Example: controlPlane: secrets: - Secret: postgres-postgresql Key: postgresql-password Env: KUMA_STORE_POSTGRES_PASSWORD | +| postgres.tls.mode | string | `"disable"` | Mode of TLS connection. Available values are: "disable", "verifyNone", "verifyCa", "verifyFull" | +| postgres.tls.disableSSLSNI | bool | `false` | Whether to disable SNI the postgres `sslsni` option. | +| postgres.tls.caSecretName | string | `nil` | Secret name that contains the ca.crt | +| postgres.tls.secretName | string | `nil` | Secret name that contains the client tls.crt, tls.key | + +## Custom Resource Definitions + +All Kuma CRDs are loaded via the [`crds`](crds) directory. For more detailed information on CRDs and Helm, +please refer to [the Helm documentation][helm-crd]. + +## Deleting + +As part of [Helm's limitations][helm-crd-limitations], CRDs will not be deleted when the `kuma` chart is deleted and +must be deleted manually. When a CRD is deleted Kubernetes deletes all resources of that kind as well, so this should +be done carefully. + +To do this with `kubectl` on *nix platforms, run: + +```shell +kubectl get crds | grep kuma.io | tr -s " " | cut -d " " -f1 | xargs kubectl delete crd + +# or with jq +kubectl get crds -o json | jq '.items[].metadata.name | select(.|test(".*kuma\\.io"))' | xargs kubectl delete crd +``` + +## Autoscaling + +In production, it is advisable to enable Control Plane autoscaling for High Availability. Autoscaling uses the +`HorizontalPodAutoscaler` resource to add redundancy and scale the CP pods based on CPU utilization, which requires +the [k8s metrics-server][kube-metrics-server] to be running on the cluster. + +## Development + +The charts are used internally in `kumactl install`, therefore the following rules apply when developing new chat features: + * all templates that start with `pre-` and `post-` are omitted when processing in `kumactl install` + +### Installing Metrics Server for Autoscaling + +If running on kind, or on a cluster with a similarly self-signed cert, the metrics server must be configured to allow +insecure kubelet TLS. The make task `kind/deploy/metrics-server` installs this patched version of the server. + +[kuma-url]: https://kuma.io/ +[kuma-logo]: https://kuma-public-assets.s3.amazonaws.com/kuma-logo-v2.png +[helm-crd]: https://helm.sh/docs/chart_best_practices/custom_resource_definitions/ +[helm-crd-limitations]: https://helm.sh/docs/topics/charts/#limitations-on-crds +[kube-metrics-server]: https://github.com/kubernetes-sigs/metrics-server diff --git a/charts/kuma/kuma/2.8.2/README.md.gotmpl b/charts/kuma/kuma/2.8.2/README.md.gotmpl new file mode 100644 index 000000000..3b296a411 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/README.md.gotmpl @@ -0,0 +1,52 @@ +[![][kuma-logo]][kuma-url] + +{{ template "chart.description" . }} + +{{ template "chart.typeBadge" . }}{{ template "chart.versionBadge" . }}{{ template "chart.appVersionBadge" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.valuesSection" . }} + +## Custom Resource Definitions + +All Kuma CRDs are loaded via the [`crds`](crds) directory. For more detailed information on CRDs and Helm, +please refer to [the Helm documentation][helm-crd]. + +## Deleting + +As part of [Helm's limitations][helm-crd-limitations], CRDs will not be deleted when the `kuma` chart is deleted and +must be deleted manually. When a CRD is deleted Kubernetes deletes all resources of that kind as well, so this should +be done carefully. + +To do this with `kubectl` on *nix platforms, run: + +```shell +kubectl get crds | grep kuma.io | tr -s " " | cut -d " " -f1 | xargs kubectl delete crd + +# or with jq +kubectl get crds -o json | jq '.items[].metadata.name | select(.|test(".*kuma\\.io"))' | xargs kubectl delete crd +``` + +## Autoscaling + +In production, it is advisable to enable Control Plane autoscaling for High Availability. Autoscaling uses the +`HorizontalPodAutoscaler` resource to add redundancy and scale the CP pods based on CPU utilization, which requires +the [k8s metrics-server][kube-metrics-server] to be running on the cluster. + +## Development + +The charts are used internally in `kumactl install`, therefore the following rules apply when developing new chat features: + * all templates that start with `pre-` and `post-` are omitted when processing in `kumactl install` + +### Installing Metrics Server for Autoscaling + +If running on kind, or on a cluster with a similarly self-signed cert, the metrics server must be configured to allow +insecure kubelet TLS. The make task `kind/deploy/metrics-server` installs this patched version of the server. + + +[kuma-url]: https://kuma.io/ +[kuma-logo]: https://kuma-public-assets.s3.amazonaws.com/kuma-logo-v2.png +[helm-crd]: https://helm.sh/docs/chart_best_practices/custom_resource_definitions/ +[helm-crd-limitations]: https://helm.sh/docs/topics/charts/#limitations-on-crds +[kube-metrics-server]: https://github.com/kubernetes-sigs/metrics-server diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_circuitbreakers.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_circuitbreakers.yaml new file mode 100644 index 000000000..449e4eb81 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_circuitbreakers.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: circuitbreakers.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: CircuitBreaker + listKind: CircuitBreakerList + plural: circuitbreakers + singular: circuitbreaker + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma CircuitBreaker resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_containerpatches.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_containerpatches.yaml new file mode 100644 index 000000000..654bbf928 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_containerpatches.yaml @@ -0,0 +1,114 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: containerpatches.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ContainerPatch + listKind: ContainerPatchList + plural: containerpatches + singular: containerpatch + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: ContainerPatch stores a list of patches to apply to init and + sidecar containers. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + type: string + metadata: + type: object + spec: + description: ContainerPatchSpec specifies the options available for a + ContainerPatch + properties: + initPatch: + description: InitPatch specifies jsonpatch to apply to an init container. + items: + description: JsonPatchBlock is one json patch operation block. + properties: + from: + description: From is a jsonpatch from string, used by move and + copy operations. + type: string + op: + description: Op is a jsonpatch operation string. + enum: + - add + - remove + - replace + - move + - copy + type: string + path: + description: Path is a jsonpatch path string. + type: string + value: + description: |- + Value must be a string representing a valid json object used + by replace and add operations. String has to be escaped with " to be valid a json object. + type: string + required: + - op + - path + type: object + type: array + sidecarPatch: + description: SidecarPatch specifies jsonpatch to apply to a sidecar + container. + items: + description: JsonPatchBlock is one json patch operation block. + properties: + from: + description: From is a jsonpatch from string, used by move and + copy operations. + type: string + op: + description: Op is a jsonpatch operation string. + enum: + - add + - remove + - replace + - move + - copy + type: string + path: + description: Path is a jsonpatch path string. + type: string + value: + description: |- + Value must be a string representing a valid json object used + by replace and add operations. String has to be escaped with " to be valid a json object. + type: string + required: + - op + - path + type: object + type: array + type: object + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_dataplaneinsights.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_dataplaneinsights.yaml new file mode 100644 index 000000000..b184e1955 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_dataplaneinsights.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: dataplaneinsights.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: DataplaneInsight + listKind: DataplaneInsightList + plural: dataplaneinsights + singular: dataplaneinsight + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + status: + description: Status is the status the Kuma resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_dataplanes.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_dataplanes.yaml new file mode 100644 index 000000000..9d0be07cd --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_dataplanes.yaml @@ -0,0 +1,70 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: dataplanes.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: Dataplane + listKind: DataplaneList + plural: dataplanes + singular: dataplane + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Service tag of the first inbound + jsonPath: .spec.networking.inbound[0].tags['kuma\.io/service'] + name: kuma.io/service + type: string + - description: Service tag of the second inbound + jsonPath: .spec.networking.inbound[1].tags['kuma\.io/service'] + name: kuma.io/service + type: string + - description: Service tag of the third inbound + jsonPath: .spec.networking.inbound[2].tags['kuma\.io/service'] + name: kuma.io/service + priority: 1 + type: string + - description: Service tag of the fourth inbound + jsonPath: .spec.networking.inbound[3].tags['kuma\.io/service'] + name: kuma.io/service + priority: 1 + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma Dataplane resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_externalservices.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_externalservices.yaml new file mode 100644 index 000000000..038ea3f7a --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_externalservices.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: externalservices.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ExternalService + listKind: ExternalServiceList + plural: externalservices + singular: externalservice + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma ExternalService resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_faultinjections.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_faultinjections.yaml new file mode 100644 index 000000000..93ce367fc --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_faultinjections.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: faultinjections.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: FaultInjection + listKind: FaultInjectionList + plural: faultinjections + singular: faultinjection + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma FaultInjection resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_healthchecks.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_healthchecks.yaml new file mode 100644 index 000000000..9599e09dd --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_healthchecks.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: healthchecks.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: HealthCheck + listKind: HealthCheckList + plural: healthchecks + singular: healthcheck + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma HealthCheck resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_hostnamegenerators.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_hostnamegenerators.yaml new file mode 100644 index 000000000..289ba10ce --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_hostnamegenerators.yaml @@ -0,0 +1,65 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: hostnamegenerators.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: HostnameGenerator + listKind: HostnameGeneratorList + plural: hostnamegenerators + singular: hostnamegenerator + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma HostnameGenerator resource. + properties: + selector: + properties: + meshExternalService: + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + meshService: + properties: + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + template: + type: string + type: object + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshaccesslogs.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshaccesslogs.yaml new file mode 100644 index 000000000..61cb8c28a --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshaccesslogs.yaml @@ -0,0 +1,556 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshaccesslogs.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshAccessLog + listKind: MeshAccessLogList + plural: meshaccesslogs + singular: meshaccesslog + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshAccessLog resource. + properties: + from: + description: From list makes a match between clients and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of clients referenced in + 'targetRef' + properties: + backends: + items: + properties: + file: + description: FileBackend defines configuration for + file based access logs + properties: + format: + description: |- + Format of access logs. Placeholders available on + https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators + properties: + json: + example: + - key: start_time + value: '%START_TIME%' + - key: bytes_received + value: '%BYTES_RECEIVED%' + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + omitEmptyValues: + default: false + type: boolean + plain: + example: '[%START_TIME%] %KUMA_MESH% %UPSTREAM_HOST%' + type: string + type: + enum: + - Plain + - Json + type: string + required: + - type + type: object + path: + description: Path to a file that logs will be + written to + example: /tmp/access.log + minLength: 1 + type: string + required: + - path + type: object + openTelemetry: + description: Defines an OpenTelemetry logging backend. + properties: + attributes: + description: |- + Attributes can contain placeholders available on + https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators + example: + - key: mesh + value: '%KUMA_MESH%' + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + body: + description: |- + Body is a raw string or an OTLP any value as described at + https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-body + It can contain placeholders available on + https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators + example: + kvlistValue: + values: + - key: mesh + value: + stringValue: '%KUMA_MESH%' + x-kubernetes-preserve-unknown-fields: true + endpoint: + description: Endpoint of OpenTelemetry collector. + An empty port defaults to 4317. + example: otel-collector:4317 + minLength: 1 + type: string + required: + - endpoint + type: object + tcp: + description: TCPBackend defines a TCP logging backend. + properties: + address: + description: Address of the TCP logging backend + example: 127.0.0.1:5000 + minLength: 1 + type: string + format: + description: |- + Format of access logs. Placeholders available on + https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators + properties: + json: + example: + - key: start_time + value: '%START_TIME%' + - key: bytes_received + value: '%BYTES_RECEIVED%' + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + omitEmptyValues: + default: false + type: boolean + plain: + example: '[%START_TIME%] %KUMA_MESH% %UPSTREAM_HOST%' + type: string + type: + enum: + - Plain + - Json + type: string + required: + - type + type: object + required: + - address + type: object + type: + enum: + - Tcp + - File + - OpenTelemetry + type: string + required: + - type + type: object + type: array + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + clients. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined in-place. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: To list makes a match between the consumed services and + corresponding configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations referenced in + 'targetRef' + properties: + backends: + items: + properties: + file: + description: FileBackend defines configuration for + file based access logs + properties: + format: + description: |- + Format of access logs. Placeholders available on + https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators + properties: + json: + example: + - key: start_time + value: '%START_TIME%' + - key: bytes_received + value: '%BYTES_RECEIVED%' + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + omitEmptyValues: + default: false + type: boolean + plain: + example: '[%START_TIME%] %KUMA_MESH% %UPSTREAM_HOST%' + type: string + type: + enum: + - Plain + - Json + type: string + required: + - type + type: object + path: + description: Path to a file that logs will be + written to + example: /tmp/access.log + minLength: 1 + type: string + required: + - path + type: object + openTelemetry: + description: Defines an OpenTelemetry logging backend. + properties: + attributes: + description: |- + Attributes can contain placeholders available on + https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators + example: + - key: mesh + value: '%KUMA_MESH%' + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + body: + description: |- + Body is a raw string or an OTLP any value as described at + https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-body + It can contain placeholders available on + https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators + example: + kvlistValue: + values: + - key: mesh + value: + stringValue: '%KUMA_MESH%' + x-kubernetes-preserve-unknown-fields: true + endpoint: + description: Endpoint of OpenTelemetry collector. + An empty port defaults to 4317. + example: otel-collector:4317 + minLength: 1 + type: string + required: + - endpoint + type: object + tcp: + description: TCPBackend defines a TCP logging backend. + properties: + address: + description: Address of the TCP logging backend + example: 127.0.0.1:5000 + minLength: 1 + type: string + format: + description: |- + Format of access logs. Placeholders available on + https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage#command-operators + properties: + json: + example: + - key: start_time + value: '%START_TIME%' + - key: bytes_received + value: '%BYTES_RECEIVED%' + items: + properties: + key: + type: string + value: + type: string + type: object + type: array + omitEmptyValues: + default: false + type: boolean + plain: + example: '[%START_TIME%] %KUMA_MESH% %UPSTREAM_HOST%' + type: string + type: + enum: + - Plain + - Json + type: string + required: + - type + type: object + required: + - address + type: object + type: + enum: + - Tcp + - File + - OpenTelemetry + type: string + required: + - type + type: object + type: array + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshcircuitbreakers.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshcircuitbreakers.yaml new file mode 100644 index 000000000..b0b848b52 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshcircuitbreakers.yaml @@ -0,0 +1,738 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshcircuitbreakers.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshCircuitBreaker + listKind: MeshCircuitBreakerList + plural: meshcircuitbreakers + singular: meshcircuitbreaker + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshCircuitBreaker + resource. + properties: + from: + description: From list makes a match between clients and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations + referenced in 'targetRef' + properties: + connectionLimits: + description: |- + ConnectionLimits contains configuration of each circuit breaking limit, + which when exceeded makes the circuit breaker to become open (no traffic + is allowed like no current is allowed in the circuits when physical + circuit breaker ir open) + properties: + maxConnectionPools: + description: |- + The maximum number of connection pools per cluster that are concurrently + supported at once. Set this for clusters which create a large number of + connection pools. + format: int32 + type: integer + maxConnections: + description: |- + The maximum number of connections allowed to be made to the upstream + cluster. + format: int32 + type: integer + maxPendingRequests: + description: |- + The maximum number of pending requests that are allowed to the upstream + cluster. This limit is applied as a connection limit for non-HTTP + traffic. + format: int32 + type: integer + maxRequests: + description: |- + The maximum number of parallel requests that are allowed to be made + to the upstream cluster. This limit does not apply to non-HTTP traffic. + format: int32 + type: integer + maxRetries: + description: |- + The maximum number of parallel retries that will be allowed to + the upstream cluster. + format: int32 + type: integer + type: object + outlierDetection: + description: |- + OutlierDetection contains the configuration of the process of dynamically + determining whether some number of hosts in an upstream cluster are + performing unlike the others and removing them from the healthy load + balancing set. Performance might be along different axes such as + consecutive failures, temporal success rate, temporal latency, etc. + Outlier detection is a form of passive health checking. + properties: + baseEjectionTime: + description: |- + The base time that a host is ejected for. The real time is equal to + the base time multiplied by the number of times the host has been + ejected. + type: string + detectors: + description: Contains configuration for supported outlier + detectors + properties: + failurePercentage: + description: |- + Failure Percentage based outlier detection functions similarly to success + rate detection, in that it relies on success rate data from each host in + a cluster. However, rather than compare those values to the mean success + rate of the cluster as a whole, they are compared to a flat + user-configured threshold. This threshold is configured via the + outlierDetection.failurePercentageThreshold field. + The other configuration fields for failure percentage based detection are + similar to the fields for success rate detection. As with success rate + detection, detection will not be performed for a host if its request + volume over the aggregation interval is less than the + outlierDetection.detectors.failurePercentage.requestVolume value. + Detection also will not be performed for a cluster if the number of hosts + with the minimum required request volume in an interval is less than the + outlierDetection.detectors.failurePercentage.minimumHosts value. + properties: + minimumHosts: + description: |- + The minimum number of hosts in a cluster in order to perform failure + percentage-based ejection. If the total number of hosts in the cluster is + less than this value, failure percentage-based ejection will not be + performed. + format: int32 + type: integer + requestVolume: + description: |- + The minimum number of total requests that must be collected in one + interval (as defined by the interval duration above) to perform failure + percentage-based ejection for this host. If the volume is lower than this + setting, failure percentage-based ejection will not be performed for this + host. + format: int32 + type: integer + threshold: + description: |- + The failure percentage to use when determining failure percentage-based + outlier detection. If the failure percentage of a given host is greater + than or equal to this value, it will be ejected. + format: int32 + type: integer + type: object + gatewayFailures: + description: |- + In the default mode (outlierDetection.splitExternalLocalOriginErrors is + false) this detection type takes into account a subset of 5xx errors, + called "gateway errors" (502, 503 or 504 status code) and local origin + failures, such as timeout, TCP reset etc. + In split mode (outlierDetection.splitExternalLocalOriginErrors is true) + this detection type takes into account a subset of 5xx errors, called + "gateway errors" (502, 503 or 504 status code) and is supported only by + the http router. + properties: + consecutive: + description: |- + The number of consecutive gateway failures (502, 503, 504 status codes) + before a consecutive gateway failure ejection occurs. + format: int32 + type: integer + type: object + localOriginFailures: + description: |- + This detection type is enabled only when + outlierDetection.splitExternalLocalOriginErrors is true and takes into + account only locally originated errors (timeout, reset, etc). + If Envoy repeatedly cannot connect to an upstream host or communication + with the upstream host is repeatedly interrupted, it will be ejected. + Various locally originated problems are detected: timeout, TCP reset, + ICMP errors, etc. This detection type is supported by http router and + tcp proxy. + properties: + consecutive: + description: |- + The number of consecutive locally originated failures before ejection + occurs. Parameter takes effect only when splitExternalAndLocalErrors + is set to true. + format: int32 + type: integer + type: object + successRate: + description: |- + Success Rate based outlier detection aggregates success rate data from + every host in a cluster. Then at given intervals ejects hosts based on + statistical outlier detection. Success Rate outlier detection will not be + calculated for a host if its request volume over the aggregation interval + is less than the outlierDetection.detectors.successRate.requestVolume + value. + Moreover, detection will not be performed for a cluster if the number of + hosts with the minimum required request volume in an interval is less + than the outlierDetection.detectors.successRate.minimumHosts value. + In the default configuration mode + (outlierDetection.splitExternalLocalOriginErrors is false) this detection + type takes into account all types of errors: locally and externally + originated. + In split mode (outlierDetection.splitExternalLocalOriginErrors is true), + locally originated errors and externally originated (transaction) errors + are counted and treated separately. + properties: + minimumHosts: + description: |- + The number of hosts in a cluster that must have enough request volume to + detect success rate outliers. If the number of hosts is less than this + setting, outlier detection via success rate statistics is not performed + for any host in the cluster. + format: int32 + type: integer + requestVolume: + description: |- + The minimum number of total requests that must be collected in one + interval (as defined by the interval duration configured in + outlierDetection section) to include this host in success rate based + outlier detection. If the volume is lower than this setting, outlier + detection via success rate statistics is not performed for that host. + format: int32 + type: integer + standardDeviationFactor: + anyOf: + - type: integer + - type: string + description: |- + This factor is used to determine the ejection threshold for success rate + outlier ejection. The ejection threshold is the difference between + the mean success rate, and the product of this factor and the standard + deviation of the mean success rate: mean - (standard_deviation * + success_rate_standard_deviation_factor). + Either int or decimal represented as string. + x-kubernetes-int-or-string: true + type: object + totalFailures: + description: |- + In the default mode (outlierDetection.splitExternalAndLocalErrors is + false) this detection type takes into account all generated errors: + locally originated and externally originated (transaction) errors. + In split mode (outlierDetection.splitExternalLocalOriginErrors is true) + this detection type takes into account only externally originated + (transaction) errors, ignoring locally originated errors. + If an upstream host is an HTTP-server, only 5xx types of error are taken + into account (see Consecutive Gateway Failure for exceptions). + Properly formatted responses, even when they carry an operational error + (like index not found, access denied) are not taken into account. + properties: + consecutive: + description: |- + The number of consecutive server-side error responses (for HTTP traffic, + 5xx responses; for TCP traffic, connection failures; for Redis, failure + to respond PONG; etc.) before a consecutive total failure ejection + occurs. + format: int32 + type: integer + type: object + type: object + disabled: + description: When set to true, outlierDetection configuration + won't take any effect + type: boolean + interval: + description: |- + The time interval between ejection analysis sweeps. This can result in + both new ejections and hosts being returned to service. + type: string + maxEjectionPercent: + description: |- + The maximum % of an upstream cluster that can be ejected due to outlier + detection. Defaults to 10% but will eject at least one host regardless of + the value. + format: int32 + type: integer + splitExternalAndLocalErrors: + description: |- + Determines whether to distinguish local origin failures from external + errors. If set to true the following configuration parameters are taken + into account: detectors.localOriginFailures.consecutive + type: boolean + type: object + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined in place. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: |- + To list makes a match between the consumed services and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations + referenced in 'targetRef' + properties: + connectionLimits: + description: |- + ConnectionLimits contains configuration of each circuit breaking limit, + which when exceeded makes the circuit breaker to become open (no traffic + is allowed like no current is allowed in the circuits when physical + circuit breaker ir open) + properties: + maxConnectionPools: + description: |- + The maximum number of connection pools per cluster that are concurrently + supported at once. Set this for clusters which create a large number of + connection pools. + format: int32 + type: integer + maxConnections: + description: |- + The maximum number of connections allowed to be made to the upstream + cluster. + format: int32 + type: integer + maxPendingRequests: + description: |- + The maximum number of pending requests that are allowed to the upstream + cluster. This limit is applied as a connection limit for non-HTTP + traffic. + format: int32 + type: integer + maxRequests: + description: |- + The maximum number of parallel requests that are allowed to be made + to the upstream cluster. This limit does not apply to non-HTTP traffic. + format: int32 + type: integer + maxRetries: + description: |- + The maximum number of parallel retries that will be allowed to + the upstream cluster. + format: int32 + type: integer + type: object + outlierDetection: + description: |- + OutlierDetection contains the configuration of the process of dynamically + determining whether some number of hosts in an upstream cluster are + performing unlike the others and removing them from the healthy load + balancing set. Performance might be along different axes such as + consecutive failures, temporal success rate, temporal latency, etc. + Outlier detection is a form of passive health checking. + properties: + baseEjectionTime: + description: |- + The base time that a host is ejected for. The real time is equal to + the base time multiplied by the number of times the host has been + ejected. + type: string + detectors: + description: Contains configuration for supported outlier + detectors + properties: + failurePercentage: + description: |- + Failure Percentage based outlier detection functions similarly to success + rate detection, in that it relies on success rate data from each host in + a cluster. However, rather than compare those values to the mean success + rate of the cluster as a whole, they are compared to a flat + user-configured threshold. This threshold is configured via the + outlierDetection.failurePercentageThreshold field. + The other configuration fields for failure percentage based detection are + similar to the fields for success rate detection. As with success rate + detection, detection will not be performed for a host if its request + volume over the aggregation interval is less than the + outlierDetection.detectors.failurePercentage.requestVolume value. + Detection also will not be performed for a cluster if the number of hosts + with the minimum required request volume in an interval is less than the + outlierDetection.detectors.failurePercentage.minimumHosts value. + properties: + minimumHosts: + description: |- + The minimum number of hosts in a cluster in order to perform failure + percentage-based ejection. If the total number of hosts in the cluster is + less than this value, failure percentage-based ejection will not be + performed. + format: int32 + type: integer + requestVolume: + description: |- + The minimum number of total requests that must be collected in one + interval (as defined by the interval duration above) to perform failure + percentage-based ejection for this host. If the volume is lower than this + setting, failure percentage-based ejection will not be performed for this + host. + format: int32 + type: integer + threshold: + description: |- + The failure percentage to use when determining failure percentage-based + outlier detection. If the failure percentage of a given host is greater + than or equal to this value, it will be ejected. + format: int32 + type: integer + type: object + gatewayFailures: + description: |- + In the default mode (outlierDetection.splitExternalLocalOriginErrors is + false) this detection type takes into account a subset of 5xx errors, + called "gateway errors" (502, 503 or 504 status code) and local origin + failures, such as timeout, TCP reset etc. + In split mode (outlierDetection.splitExternalLocalOriginErrors is true) + this detection type takes into account a subset of 5xx errors, called + "gateway errors" (502, 503 or 504 status code) and is supported only by + the http router. + properties: + consecutive: + description: |- + The number of consecutive gateway failures (502, 503, 504 status codes) + before a consecutive gateway failure ejection occurs. + format: int32 + type: integer + type: object + localOriginFailures: + description: |- + This detection type is enabled only when + outlierDetection.splitExternalLocalOriginErrors is true and takes into + account only locally originated errors (timeout, reset, etc). + If Envoy repeatedly cannot connect to an upstream host or communication + with the upstream host is repeatedly interrupted, it will be ejected. + Various locally originated problems are detected: timeout, TCP reset, + ICMP errors, etc. This detection type is supported by http router and + tcp proxy. + properties: + consecutive: + description: |- + The number of consecutive locally originated failures before ejection + occurs. Parameter takes effect only when splitExternalAndLocalErrors + is set to true. + format: int32 + type: integer + type: object + successRate: + description: |- + Success Rate based outlier detection aggregates success rate data from + every host in a cluster. Then at given intervals ejects hosts based on + statistical outlier detection. Success Rate outlier detection will not be + calculated for a host if its request volume over the aggregation interval + is less than the outlierDetection.detectors.successRate.requestVolume + value. + Moreover, detection will not be performed for a cluster if the number of + hosts with the minimum required request volume in an interval is less + than the outlierDetection.detectors.successRate.minimumHosts value. + In the default configuration mode + (outlierDetection.splitExternalLocalOriginErrors is false) this detection + type takes into account all types of errors: locally and externally + originated. + In split mode (outlierDetection.splitExternalLocalOriginErrors is true), + locally originated errors and externally originated (transaction) errors + are counted and treated separately. + properties: + minimumHosts: + description: |- + The number of hosts in a cluster that must have enough request volume to + detect success rate outliers. If the number of hosts is less than this + setting, outlier detection via success rate statistics is not performed + for any host in the cluster. + format: int32 + type: integer + requestVolume: + description: |- + The minimum number of total requests that must be collected in one + interval (as defined by the interval duration configured in + outlierDetection section) to include this host in success rate based + outlier detection. If the volume is lower than this setting, outlier + detection via success rate statistics is not performed for that host. + format: int32 + type: integer + standardDeviationFactor: + anyOf: + - type: integer + - type: string + description: |- + This factor is used to determine the ejection threshold for success rate + outlier ejection. The ejection threshold is the difference between + the mean success rate, and the product of this factor and the standard + deviation of the mean success rate: mean - (standard_deviation * + success_rate_standard_deviation_factor). + Either int or decimal represented as string. + x-kubernetes-int-or-string: true + type: object + totalFailures: + description: |- + In the default mode (outlierDetection.splitExternalAndLocalErrors is + false) this detection type takes into account all generated errors: + locally originated and externally originated (transaction) errors. + In split mode (outlierDetection.splitExternalLocalOriginErrors is true) + this detection type takes into account only externally originated + (transaction) errors, ignoring locally originated errors. + If an upstream host is an HTTP-server, only 5xx types of error are taken + into account (see Consecutive Gateway Failure for exceptions). + Properly formatted responses, even when they carry an operational error + (like index not found, access denied) are not taken into account. + properties: + consecutive: + description: |- + The number of consecutive server-side error responses (for HTTP traffic, + 5xx responses; for TCP traffic, connection failures; for Redis, failure + to respond PONG; etc.) before a consecutive total failure ejection + occurs. + format: int32 + type: integer + type: object + type: object + disabled: + description: When set to true, outlierDetection configuration + won't take any effect + type: boolean + interval: + description: |- + The time interval between ejection analysis sweeps. This can result in + both new ejections and hosts being returned to service. + type: string + maxEjectionPercent: + description: |- + The maximum % of an upstream cluster that can be ejected due to outlier + detection. Defaults to 10% but will eject at least one host regardless of + the value. + format: int32 + type: integer + splitExternalAndLocalErrors: + description: |- + Determines whether to distinguish local origin failures from external + errors. If set to true the following configuration parameters are taken + into account: detectors.localOriginFailures.consecutive + type: boolean + type: object + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshes.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshes.yaml new file mode 100644 index 000000000..5b7a9fd65 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshes.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshes.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: Mesh + listKind: MeshList + plural: meshes + singular: mesh + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma Mesh resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshexternalservices.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshexternalservices.yaml new file mode 100644 index 000000000..6108163ca --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshexternalservices.yaml @@ -0,0 +1,333 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshexternalservices.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshExternalService + listKind: MeshExternalServiceList + plural: meshexternalservices + singular: meshexternalservice + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshExternalService + resource. + properties: + endpoints: + description: Endpoints defines a list of destinations to send traffic + to. + items: + properties: + address: + description: Address defines an address to which a user want + to send a request. Is possible to provide `domain`, `ip` and + `unix` sockets. + example: unix:///tmp/example.sock + minLength: 1 + type: string + port: + description: Port of the endpoint + maximum: 65535 + minimum: 1 + type: integer + required: + - address + type: object + type: array + extension: + description: Extension struct for a plugin configuration, in the presence + of an extension `endpoints` and `tls` are not required anymore - + it's up to the extension to validate them independently. + properties: + config: + description: Config freeform configuration for the extension. + x-kubernetes-preserve-unknown-fields: true + type: + description: Type of the extension. + type: string + required: + - config + - type + type: object + match: + description: Match defines traffic that should be routed through the + sidecar. + properties: + port: + description: Port defines a port to which a user does request. + maximum: 65535 + minimum: 1 + type: integer + protocol: + default: tcp + description: 'Protocol defines a protocol of the communication. + Possible values: `tcp`, `grpc`, `http`, `http2`.' + enum: + - tcp + - grpc + - http + - http2 + type: string + type: + default: HostnameGenerator + description: Type of the match, only `HostnameGenerator` is available + at the moment. + enum: + - HostnameGenerator + type: string + required: + - port + type: object + tls: + description: Tls provides a TLS configuration when proxy is resposible + for a TLS origination + properties: + allowRenegotiation: + default: false + description: |- + AllowRenegotiation defines if TLS sessions will allow renegotiation. + Setting this to true is not recommended for security reasons. + type: boolean + enabled: + default: false + description: Enabled defines if proxy should originate TLS. + type: boolean + verification: + description: Verification section for providing TLS verification + details. + properties: + caCert: + description: CaCert defines a certificate of CA. + properties: + inline: + description: Data source is inline bytes. + format: byte + type: string + inlineString: + description: Data source is inline string` + type: string + secret: + description: Data source is a secret with given Secret + key. + type: string + type: object + clientCert: + description: ClientCert defines a certificate of a client. + properties: + inline: + description: Data source is inline bytes. + format: byte + type: string + inlineString: + description: Data source is inline string` + type: string + secret: + description: Data source is a secret with given Secret + key. + type: string + type: object + clientKey: + description: ClientKey defines a client private key. + properties: + inline: + description: Data source is inline bytes. + format: byte + type: string + inlineString: + description: Data source is inline string` + type: string + secret: + description: Data source is a secret with given Secret + key. + type: string + type: object + mode: + default: Secured + description: Mode defines if proxy should skip verification, + one of `SkipSAN`, `SkipCA`, `Secured`, `SkipAll`. Default + `Secured`. + enum: + - SkipSAN + - SkipCA + - Secured + - SkipAll + type: string + serverName: + description: ServerName overrides the default Server Name + Indicator set by Kuma. + type: string + subjectAltNames: + description: SubjectAltNames list of names to verify in the + certificate. + items: + properties: + type: + default: Exact + description: 'Type specifies matching type, one of `Exact`, + `Prefix`. Default: `Exact`' + enum: + - Exact + - Prefix + type: string + value: + description: Value to match. + type: string + required: + - value + type: object + type: array + type: object + version: + description: Version section for providing version specification. + properties: + max: + default: TLSAuto + description: Max defines maximum supported version. One of + `TLSAuto`, `TLS10`, `TLS11`, `TLS12`, `TLS13`. + enum: + - TLSAuto + - TLS10 + - TLS11 + - TLS12 + - TLS13 + type: string + min: + default: TLSAuto + description: Min defines minimum supported version. One of + `TLSAuto`, `TLS10`, `TLS11`, `TLS12`, `TLS13`. + enum: + - TLSAuto + - TLS10 + - TLS11 + - TLS12 + - TLS13 + type: string + type: object + type: object + required: + - match + type: object + status: + description: Status is the current status of the Kuma MeshExternalService + resource. + properties: + addresses: + description: Addresses section for generated domains + items: + properties: + hostname: + type: string + hostnameGeneratorRef: + properties: + coreName: + type: string + required: + - coreName + type: object + origin: + type: string + type: object + type: array + hostnameGenerators: + items: + properties: + conditions: + description: Conditions is an array of hostname generator conditions. + items: + properties: + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + hostnameGeneratorRef: + properties: + coreName: + type: string + required: + - coreName + type: object + required: + - hostnameGeneratorRef + type: object + type: array + vip: + description: Vip section for allocated IP + properties: + ip: + description: Value allocated IP for a provided domain with `HostnameGenerator` + type in a match section. + type: string + type: object + type: object + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshfaultinjections.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshfaultinjections.yaml new file mode 100644 index 000000000..e3ccb0b24 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshfaultinjections.yaml @@ -0,0 +1,419 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshfaultinjections.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshFaultInjection + listKind: MeshFaultInjectionList + plural: meshfaultinjections + singular: meshfaultinjection + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshFaultInjection + resource. + properties: + from: + description: From list makes a match between clients and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations referenced in + 'targetRef' + properties: + http: + description: Http allows to define list of Http faults between + dataplanes. + items: + description: FaultInjection defines the configuration + of faults between dataplanes. + properties: + abort: + description: |- + Abort defines a configuration of not delivering requests to destination + service and replacing the responses from destination dataplane by + predefined status code + properties: + httpStatus: + description: HTTP status code which will be returned + to source side + format: int32 + type: integer + percentage: + anyOf: + - type: integer + - type: string + description: |- + Percentage of requests on which abort will be injected, has to be + either int or decimal represented as string. + x-kubernetes-int-or-string: true + required: + - httpStatus + - percentage + type: object + delay: + description: Delay defines configuration of delaying + a response from a destination + properties: + percentage: + anyOf: + - type: integer + - type: string + description: |- + Percentage of requests on which delay will be injected, has to be + either int or decimal represented as string. + x-kubernetes-int-or-string: true + value: + description: The duration during which the response + will be delayed + type: string + required: + - percentage + - value + type: object + responseBandwidth: + description: |- + ResponseBandwidth defines a configuration to limit the speed of + responding to the requests + properties: + limit: + description: |- + Limit is represented by value measure in Gbps, Mbps, kbps, e.g. + 10kbps + type: string + percentage: + anyOf: + - type: integer + - type: string + description: |- + Percentage of requests on which response bandwidth limit will be + either int or decimal represented as string. + x-kubernetes-int-or-string: true + required: + - limit + - percentage + type: object + type: object + type: array + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: To list makes a match between clients and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations referenced in + 'targetRef' + properties: + http: + description: Http allows to define list of Http faults between + dataplanes. + items: + description: FaultInjection defines the configuration + of faults between dataplanes. + properties: + abort: + description: |- + Abort defines a configuration of not delivering requests to destination + service and replacing the responses from destination dataplane by + predefined status code + properties: + httpStatus: + description: HTTP status code which will be returned + to source side + format: int32 + type: integer + percentage: + anyOf: + - type: integer + - type: string + description: |- + Percentage of requests on which abort will be injected, has to be + either int or decimal represented as string. + x-kubernetes-int-or-string: true + required: + - httpStatus + - percentage + type: object + delay: + description: Delay defines configuration of delaying + a response from a destination + properties: + percentage: + anyOf: + - type: integer + - type: string + description: |- + Percentage of requests on which delay will be injected, has to be + either int or decimal represented as string. + x-kubernetes-int-or-string: true + value: + description: The duration during which the response + will be delayed + type: string + required: + - percentage + - value + type: object + responseBandwidth: + description: |- + ResponseBandwidth defines a configuration to limit the speed of + responding to the requests + properties: + limit: + description: |- + Limit is represented by value measure in Gbps, Mbps, kbps, e.g. + 10kbps + type: string + percentage: + anyOf: + - type: integer + - type: string + description: |- + Percentage of requests on which response bandwidth limit will be + either int or decimal represented as string. + x-kubernetes-int-or-string: true + required: + - limit + - percentage + type: object + type: object + type: array + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgatewayinstances.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgatewayinstances.yaml new file mode 100644 index 000000000..afa0c4789 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgatewayinstances.yaml @@ -0,0 +1,364 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshgatewayinstances.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshGatewayInstance + listKind: MeshGatewayInstanceList + plural: meshgatewayinstances + singular: meshgatewayinstance + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + MeshGatewayInstance represents a managed instance of a dataplane proxy for a Kuma + Gateway. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: MeshGatewayInstanceSpec specifies the options available for + a GatewayDataplane. + properties: + podTemplate: + description: PodTemplate configures the Pod owned by this config. + properties: + metadata: + description: Metadata holds metadata configuration for a Service. + properties: + annotations: + additionalProperties: + type: string + description: Annotations holds annotations to be set on an + object. + type: object + labels: + additionalProperties: + type: string + description: Labels holds labels to be set on an objects. + type: object + type: object + spec: + description: Spec holds some customizable fields of a Pod. + properties: + container: + description: Container corresponds to PodSpec.Container + properties: + securityContext: + description: ContainerSecurityContext corresponds to PodSpec.Container.SecurityContext + properties: + readOnlyRootFilesystem: + description: ReadOnlyRootFilesystem corresponds to + PodSpec.Container.SecurityContext.ReadOnlyRootFilesystem + type: boolean + type: object + type: object + securityContext: + description: PodSecurityContext corresponds to PodSpec.SecurityContext + properties: + fsGroup: + description: FSGroup corresponds to PodSpec.SecurityContext.FSGroup + format: int64 + type: integer + type: object + serviceAccountName: + description: ServiceAccountName corresponds to PodSpec.ServiceAccountName. + type: string + type: object + type: object + replicas: + default: 1 + description: |- + Replicas is the number of dataplane proxy replicas to create. For + now this is a fixed number, but in the future it could be + automatically scaled based on metrics. + format: int32 + minimum: 1 + type: integer + resources: + description: |- + Resources specifies the compute resources for the proxy container. + The default can be set in the control plane config. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + serviceTemplate: + description: ServiceTemplate configures the Service owned by this + config. + properties: + metadata: + description: Metadata holds metadata configuration for a Service. + properties: + annotations: + additionalProperties: + type: string + description: Annotations holds annotations to be set on an + object. + type: object + labels: + additionalProperties: + type: string + description: Labels holds labels to be set on an objects. + type: object + type: object + spec: + description: Spec holds some customizable fields of a Service. + properties: + loadBalancerIP: + description: LoadBalancerIP corresponds to ServiceSpec.LoadBalancerIP. + type: string + type: object + type: object + serviceType: + default: LoadBalancer + description: |- + ServiceType specifies the type of managed Service that will be + created to expose the dataplane proxies to traffic from outside + the cluster. The ports to expose will be taken from the matching Gateway + resource. If there is no matching Gateway, the managed Service will + be deleted. + enum: + - LoadBalancer + - ClusterIP + - NodePort + type: string + tags: + additionalProperties: + type: string + description: |- + Tags specifies the Kuma tags that are propagated to the managed + dataplane proxies. These tags should include exactly one + `kuma.io/service` tag, and should match exactly one Gateway + resource. + type: object + type: object + status: + description: |- + MeshGatewayInstanceStatus holds information about the status of the gateway + instance. + properties: + conditions: + description: Conditions is an array of gateway instance conditions. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + loadBalancer: + description: |- + LoadBalancer contains the current status of the load-balancer, + if one is present. + properties: + ingress: + description: |- + Ingress is a list containing ingress points for the load-balancer. + Traffic intended for the service should be sent to these ingress points. + items: + description: |- + LoadBalancerIngress represents the status of a load-balancer ingress point: + traffic intended for the service should be sent to an ingress point. + properties: + hostname: + description: |- + Hostname is set for load-balancer ingress points that are DNS based + (typically AWS load-balancers) + type: string + ip: + description: |- + IP is set for load-balancer ingress points that are IP based + (typically GCE or OpenStack load-balancers) + type: string + ipMode: + description: |- + IPMode specifies how the load-balancer IP behaves, and may only be specified when the ip field is specified. + Setting this to "VIP" indicates that traffic is delivered to the node with + the destination set to the load-balancer's IP and port. + Setting this to "Proxy" indicates that traffic is delivered to the node or pod with + the destination set to the node's IP and node port or the pod's IP and port. + Service implementations may use this information to adjust traffic routing. + type: string + ports: + description: |- + Ports is a list of records of service ports + If used, every port defined in the service should have an entry in it + items: + properties: + error: + description: |- + Error is to record the problem with the service port + The format of the error shall comply with the following rules: + - built-in error values shall be specified in this file and those shall use + CamelCase names + - cloud provider specific error values must have names that comply with the + format foo.example.com/CamelCase. + --- + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + port: + description: Port is the port number of the service + port of which status is recorded here + format: int32 + type: integer + protocol: + default: TCP + description: |- + Protocol is the protocol of the service port of which status is recorded here + The supported values are: "TCP", "UDP", "SCTP" + type: string + required: + - port + - protocol + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: array + type: object + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgatewayroutes.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgatewayroutes.yaml new file mode 100644 index 000000000..15156ae47 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgatewayroutes.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshgatewayroutes.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshGatewayRoute + listKind: MeshGatewayRouteList + plural: meshgatewayroutes + singular: meshgatewayroute + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshGatewayRoute resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgateways.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgateways.yaml new file mode 100644 index 000000000..5ec1b4267 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshgateways.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshgateways.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshGateway + listKind: MeshGatewayList + plural: meshgateways + singular: meshgateway + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshGateway resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshhealthchecks.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshhealthchecks.yaml new file mode 100644 index 000000000..f941d27e0 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshhealthchecks.yaml @@ -0,0 +1,382 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshhealthchecks.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshHealthCheck + listKind: MeshHealthCheckList + plural: meshhealthchecks + singular: meshhealthcheck + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshHealthCheck resource. + properties: + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: To list makes a match between the consumed services and + corresponding configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations referenced in + 'targetRef' + properties: + alwaysLogHealthCheckFailures: + description: |- + If set to true, health check failure events will always be logged. If set + to false, only the initial health check failure event will be logged. The + default value is false. + type: boolean + eventLogPath: + description: |- + Specifies the path to the file where Envoy can log health check events. + If empty, no event log will be written. + type: string + failTrafficOnPanic: + description: |- + If set to true, Envoy will not consider any hosts when the cluster is in + 'panic mode'. Instead, the cluster will fail all requests as if all hosts + are unhealthy. This can help avoid potentially overwhelming a failing + service. + type: boolean + grpc: + description: |- + GrpcHealthCheck defines gRPC configuration which will instruct the service + the health check will be made for is a gRPC service. + properties: + authority: + description: |- + The value of the :authority header in the gRPC health check request, + by default name of the cluster this health check is associated with + type: string + disabled: + description: If true the GrpcHealthCheck is disabled + type: boolean + serviceName: + description: Service name parameter which will be sent + to gRPC service + type: string + type: object + healthyPanicThreshold: + anyOf: + - type: integer + - type: string + description: |- + Allows to configure panic threshold for Envoy cluster. If not specified, + the default is 50%. To disable panic mode, set to 0%. + Either int or decimal represented as string. + x-kubernetes-int-or-string: true + healthyThreshold: + default: 1 + description: Number of consecutive healthy checks before + considering a host healthy. + format: int32 + type: integer + http: + description: |- + HttpHealthCheck defines HTTP configuration which will instruct the service + the health check will be made for is an HTTP service. + properties: + disabled: + description: If true the HttpHealthCheck is disabled + type: boolean + expectedStatuses: + description: List of HTTP response statuses which are + considered healthy + items: + format: int32 + type: integer + type: array + path: + default: / + description: |- + The HTTP path which will be requested during the health check + (ie. /health) + type: string + requestHeadersToAdd: + description: |- + The list of HTTP headers which should be added to each health check + request + properties: + add: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + set: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: object + initialJitter: + description: |- + If specified, Envoy will start health checking after a random time in + ms between 0 and initialJitter. This only applies to the first health + check. + type: string + interval: + default: 1m + description: Interval between consecutive health checks. + type: string + intervalJitter: + description: |- + If specified, during every interval Envoy will add IntervalJitter to the + wait time. + type: string + intervalJitterPercent: + description: |- + If specified, during every interval Envoy will add IntervalJitter * + IntervalJitterPercent / 100 to the wait time. If IntervalJitter and + IntervalJitterPercent are both set, both of them will be used to + increase the wait time. + format: int32 + type: integer + noTrafficInterval: + description: |- + The "no traffic interval" is a special health check interval that is used + when a cluster has never had traffic routed to it. This lower interval + allows cluster information to be kept up to date, without sending a + potentially large amount of active health checking traffic for no reason. + Once a cluster has been used for traffic routing, Envoy will shift back + to using the standard health check interval that is defined. Note that + this interval takes precedence over any other. The default value for "no + traffic interval" is 60 seconds. + type: string + reuseConnection: + description: Reuse health check connection between health + checks. Default is true. + type: boolean + tcp: + description: |- + TcpHealthCheck defines configuration for specifying bytes to send and + expected response during the health check + properties: + disabled: + description: If true the TcpHealthCheck is disabled + type: boolean + receive: + description: |- + List of Base64 encoded blocks of strings expected as a response. When checking the response, + "fuzzy" matching is performed such that each block must be found, and + in the order specified, but not necessarily contiguous. + If not provided or empty, checks will be performed as "connect only" and be marked as successful when TCP connection is successfully established. + items: + type: string + type: array + send: + description: Base64 encoded content of the message which + will be sent during the health check to the target + type: string + type: object + timeout: + default: 15s + description: Maximum time to wait for a health check response. + type: string + unhealthyThreshold: + default: 5 + description: |- + Number of consecutive unhealthy checks before considering a host + unhealthy. + format: int32 + type: integer + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshhttproutes.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshhttproutes.yaml new file mode 100644 index 000000000..f4dc4952b --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshhttproutes.yaml @@ -0,0 +1,664 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshhttproutes.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshHTTPRoute + listKind: MeshHTTPRouteList + plural: meshhttproutes + singular: meshhttproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshHTTPRoute resource. + properties: + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: To matches destination services of requests and holds + configuration. + items: + properties: + hostnames: + description: |- + Hostnames is only valid when targeting MeshGateway and limits the + effects of the rules to requests to this hostname. + Given hostnames must intersect with the hostname of the listeners the + route attaches to. + items: + type: string + type: array + rules: + description: |- + Rules contains the routing rules applies to a combination of top-level + targetRef and the targetRef in this entry. + items: + properties: + default: + description: |- + Default holds routing rules that can be merged with rules from other + policies. + properties: + backendRefs: + items: + description: BackendRef defines where to forward + traffic. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use + to identify cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + port: + description: Port is only supported when this + ref refers to a real MeshService object + format: int32 + type: integer + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + weight: + default: 1 + minimum: 0 + type: integer + type: object + type: array + filters: + items: + properties: + requestHeaderModifier: + description: |- + Only one action is supported per header name. + Configuration to set or add multiple values for a header must use RFC 7230 + header value formatting, separating each value with a comma. + properties: + add: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + items: + type: string + maxItems: 16 + type: array + set: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + properties: + backendRef: + description: TODO forbid weight + properties: + kind: + description: Kind of the referenced + resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future + use to identify cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + port: + description: Port is only supported + when this ref refers to a real MeshService + object + format: int32 + type: integer + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + weight: + default: 1 + minimum: 0 + type: integer + type: object + percentage: + anyOf: + - type: integer + - type: string + description: |- + Percentage of requests to mirror. If not specified, all requests + to the target cluster will be mirrored. + x-kubernetes-int-or-string: true + required: + - backendRef + type: object + requestRedirect: + properties: + hostname: + description: |- + PreciseHostname is the fully qualified domain name of a network host. This + matches the RFC 1123 definition of a hostname with 1 notable exception that + numeric IP addresses are not allowed. + + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: |- + Path defines parameters used to modify the path of the incoming request. + The modified path is then used to construct the location header. + When empty, the request path is used as-is. + properties: + replaceFullPath: + type: string + replacePrefixMatch: + type: string + type: + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + port: + description: |- + Port is the port to be used in the value of the `Location` + header in the response. + When empty, port (if specified) of the request is used. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + enum: + - http + - https + type: string + statusCode: + default: 302 + description: StatusCode is the HTTP status + code to be used in response. + enum: + - 301 + - 302 + - 303 + - 307 + - 308 + type: integer + type: object + responseHeaderModifier: + description: |- + Only one action is supported per header name. + Configuration to set or add multiple values for a header must use RFC 7230 + header value formatting, separating each value with a comma. + properties: + add: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + items: + type: string + maxItems: 16 + type: array + set: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + type: + enum: + - RequestHeaderModifier + - ResponseHeaderModifier + - RequestRedirect + - URLRewrite + - RequestMirror + type: string + urlRewrite: + properties: + hostToBackendHostname: + description: |- + HostToBackendHostname rewrites the hostname to the hostname of the + upstream host. This option is only available when targeting MeshGateways. + type: boolean + hostname: + description: Hostname is the value to be + used to replace the host header value + during forwarding. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + path: + description: Path defines a path rewrite. + properties: + replaceFullPath: + type: string + replacePrefixMatch: + type: string + type: + enum: + - ReplaceFullPath + - ReplacePrefixMatch + type: string + required: + - type + type: object + type: object + required: + - type + type: object + type: array + type: object + matches: + description: |- + Matches describes how to match HTTP requests this rule should be applied + to. + items: + properties: + headers: + items: + description: |- + HeaderMatch describes how to select an HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name MUST be lower case + as they will be handled with case insensitivity (See https://tools.ietf.org/html/rfc7230#section-3.2). + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: Type specifies how to match against + the value of the header. + enum: + - Exact + - Present + - RegularExpression + - Absent + - Prefix + type: string + value: + description: Value is the value of HTTP Header + to be matched. + type: string + required: + - name + type: object + type: array + method: + enum: + - CONNECT + - DELETE + - GET + - HEAD + - OPTIONS + - PATCH + - POST + - PUT + - TRACE + type: string + path: + properties: + type: + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + description: |- + Exact or prefix matches must be an absolute path. A prefix matches only + if separated by a slash or the entire path. + minLength: 1 + type: string + required: + - type + - value + type: object + queryParams: + description: |- + QueryParams matches based on HTTP URL query parameters. Multiple matches + are ANDed together such that all listed matches must succeed. + items: + properties: + name: + minLength: 1 + type: string + type: + enum: + - Exact + - RegularExpression + type: string + value: + type: string + required: + - name + - type + - value + type: object + type: array + type: object + minItems: 1 + type: array + required: + - default + - matches + type: object + type: array + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + request destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshinsights.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshinsights.yaml new file mode 100644 index 000000000..c72f08ed9 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshinsights.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshinsights.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshInsight + listKind: MeshInsightList + plural: meshinsights + singular: meshinsight + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshInsight resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshloadbalancingstrategies.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshloadbalancingstrategies.yaml new file mode 100644 index 000000000..38fd712fc --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshloadbalancingstrategies.yaml @@ -0,0 +1,572 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshloadbalancingstrategies.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshLoadBalancingStrategy + listKind: MeshLoadBalancingStrategyList + plural: meshloadbalancingstrategies + singular: meshloadbalancingstrategy + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshLoadBalancingStrategy + resource. + properties: + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: To list makes a match between the consumed services and + corresponding configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations referenced in + 'targetRef' + properties: + loadBalancer: + description: LoadBalancer allows to specify load balancing + algorithm. + properties: + leastRequest: + description: |- + LeastRequest selects N random available hosts as specified in 'choiceCount' (2 by default) + and picks the host which has the fewest active requests + properties: + activeRequestBias: + anyOf: + - type: integer + - type: string + description: |- + ActiveRequestBias refers to dynamic weights applied when hosts have varying load + balancing weights. A higher value here aggressively reduces the weight of endpoints + that are currently handling active requests. In essence, the higher the ActiveRequestBias + value, the more forcefully it reduces the load balancing weight of endpoints that are + actively serving requests. + x-kubernetes-int-or-string: true + choiceCount: + description: |- + ChoiceCount is the number of random healthy hosts from which the host with + the fewest active requests will be chosen. Defaults to 2 so that Envoy performs + two-choice selection if the field is not set. + format: int32 + minimum: 2 + type: integer + type: object + maglev: + description: |- + Maglev implements consistent hashing to upstream hosts. Maglev can be used as + a drop in replacement for the ring hash load balancer any place in which + consistent hashing is desired. + properties: + hashPolicies: + description: |- + HashPolicies specify a list of request/connection properties that are used to calculate a hash. + These hash policies are executed in the specified order. If a hash policy has the “terminal” attribute + set to true, and there is already a hash generated, the hash is returned immediately, + ignoring the rest of the hash policy list. + items: + properties: + connection: + properties: + sourceIP: + description: Hash on source IP address. + type: boolean + type: object + cookie: + properties: + name: + description: The name of the cookie that + will be used to obtain the hash key. + minLength: 1 + type: string + path: + description: The name of the path for + the cookie. + type: string + ttl: + description: If specified, a cookie with + the TTL will be generated if the cookie + is not present. + type: string + required: + - name + type: object + filterState: + properties: + key: + description: |- + The name of the Object in the per-request filterState, which is + an Envoy::Hashable object. If there is no data associated with the key, + or the stored object is not Envoy::Hashable, no hash will be produced. + minLength: 1 + type: string + required: + - key + type: object + header: + properties: + name: + description: The name of the request header + that will be used to obtain the hash + key. + minLength: 1 + type: string + required: + - name + type: object + queryParameter: + properties: + name: + description: |- + The name of the URL query parameter that will be used to obtain the hash key. + If the parameter is not present, no hash will be produced. Query parameter names + are case-sensitive. + minLength: 1 + type: string + required: + - name + type: object + terminal: + description: |- + Terminal is a flag that short-circuits the hash computing. This field provides + a ‘fallback’ style of configuration: “if a terminal policy doesn’t work, fallback + to rest of the policy list”, it saves time when the terminal policy works. + If true, and there is already a hash computed, ignore rest of the list of hash polices. + type: boolean + type: + enum: + - Header + - Cookie + - SourceIP + - QueryParameter + - FilterState + type: string + required: + - type + type: object + type: array + tableSize: + description: |- + The table size for Maglev hashing. Maglev aims for “minimal disruption” + rather than an absolute guarantee. Minimal disruption means that when + the set of upstream hosts change, a connection will likely be sent + to the same upstream as it was before. Increasing the table size reduces + the amount of disruption. The table size must be prime number limited to 5000011. + If it is not specified, the default is 65537. + format: int32 + maximum: 5000011 + minimum: 1 + type: integer + type: object + random: + description: |- + Random selects a random available host. The random load balancer generally + performs better than round-robin if no health checking policy is configured. + Random selection avoids bias towards the host in the set that comes after a failed host. + type: object + ringHash: + description: |- + RingHash implements consistent hashing to upstream hosts. Each host is mapped + onto a circle (the “ring”) by hashing its address; each request is then routed + to a host by hashing some property of the request, and finding the nearest + corresponding host clockwise around the ring. + properties: + hashFunction: + description: |- + HashFunction is a function used to hash hosts onto the ketama ring. + The value defaults to XX_HASH. Available values – XX_HASH, MURMUR_HASH_2. + enum: + - XXHash + - MurmurHash2 + type: string + hashPolicies: + description: |- + HashPolicies specify a list of request/connection properties that are used to calculate a hash. + These hash policies are executed in the specified order. If a hash policy has the “terminal” attribute + set to true, and there is already a hash generated, the hash is returned immediately, + ignoring the rest of the hash policy list. + items: + properties: + connection: + properties: + sourceIP: + description: Hash on source IP address. + type: boolean + type: object + cookie: + properties: + name: + description: The name of the cookie that + will be used to obtain the hash key. + minLength: 1 + type: string + path: + description: The name of the path for + the cookie. + type: string + ttl: + description: If specified, a cookie with + the TTL will be generated if the cookie + is not present. + type: string + required: + - name + type: object + filterState: + properties: + key: + description: |- + The name of the Object in the per-request filterState, which is + an Envoy::Hashable object. If there is no data associated with the key, + or the stored object is not Envoy::Hashable, no hash will be produced. + minLength: 1 + type: string + required: + - key + type: object + header: + properties: + name: + description: The name of the request header + that will be used to obtain the hash + key. + minLength: 1 + type: string + required: + - name + type: object + queryParameter: + properties: + name: + description: |- + The name of the URL query parameter that will be used to obtain the hash key. + If the parameter is not present, no hash will be produced. Query parameter names + are case-sensitive. + minLength: 1 + type: string + required: + - name + type: object + terminal: + description: |- + Terminal is a flag that short-circuits the hash computing. This field provides + a ‘fallback’ style of configuration: “if a terminal policy doesn’t work, fallback + to rest of the policy list”, it saves time when the terminal policy works. + If true, and there is already a hash computed, ignore rest of the list of hash polices. + type: boolean + type: + enum: + - Header + - Cookie + - SourceIP + - QueryParameter + - FilterState + type: string + required: + - type + type: object + type: array + maxRingSize: + description: |- + Maximum hash ring size. Defaults to 8M entries, and limited to 8M entries, + but can be lowered to further constrain resource use. + format: int32 + maximum: 8000000 + minimum: 1 + type: integer + minRingSize: + description: |- + Minimum hash ring size. The larger the ring is (that is, + the more hashes there are for each provided host) the better the request distribution + will reflect the desired weights. Defaults to 1024 entries, and limited to 8M entries. + format: int32 + maximum: 8000000 + minimum: 1 + type: integer + type: object + roundRobin: + description: |- + RoundRobin is a load balancing algorithm that distributes requests + across available upstream hosts in round-robin order. + type: object + type: + enum: + - RoundRobin + - LeastRequest + - RingHash + - Random + - Maglev + type: string + required: + - type + type: object + localityAwareness: + description: LocalityAwareness contains configuration for + locality aware load balancing. + properties: + crossZone: + description: |- + CrossZone defines locality aware load balancing priorities when dataplane proxies inside local zone + are unavailable + properties: + failover: + description: Failover defines list of load balancing + rules in order of priority + items: + properties: + from: + description: From defines the list of zones + to which the rule applies + properties: + zones: + items: + type: string + type: array + required: + - zones + type: object + to: + description: To defines to which zones the + traffic should be load balanced + properties: + type: + description: Type defines how target zones + will be picked from available zones + enum: + - None + - Only + - Any + - AnyExcept + type: string + zones: + items: + type: string + type: array + required: + - type + type: object + required: + - to + type: object + type: array + failoverThreshold: + description: |- + FailoverThreshold defines the percentage of live destination dataplane proxies below which load balancing to the + next priority starts. + Example: If you configure failoverThreshold to 70, and you have deployed 10 destination dataplane proxies. + Load balancing to next priority will start when number of live destination dataplane proxies drops below 7. + Default 50 + properties: + percentage: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - percentage + type: object + type: object + disabled: + description: |- + Disabled allows to disable locality-aware load balancing. + When disabled requests are distributed across all endpoints regardless of locality. + type: boolean + localZone: + description: LocalZone defines locality aware load balancing + priorities between dataplane proxies inside a zone + properties: + affinityTags: + description: AffinityTags list of tags for local + zone load balancing. + items: + properties: + key: + description: Key defines tag for which affinity + is configured + type: string + weight: + description: |- + Weight of the tag used for load balancing. The bigger the weight the bigger the priority. + Percentage of local traffic load balanced to tag is computed by dividing weight by sum of weights from all tags. + For example with two affinity tags first with weight 80 and second with weight 20, + then 80% of traffic will be redirected to the first tag, and 20% of traffic will be redirected to second one. + Setting weights is not mandatory. When weights are not set control plane will compute default weight based on list order. + Default: If you do not specify weight we will adjust them so that 90% traffic goes to first tag, 9% to next, and 1% to third and so on. + format: int32 + type: integer + required: + - key + type: object + type: array + type: object + type: object + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshmetrics.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshmetrics.yaml new file mode 100644 index 000000000..260f6916e --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshmetrics.yaml @@ -0,0 +1,293 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshmetrics.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshMetric + listKind: MeshMetricList + plural: meshmetrics + singular: meshmetric + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshMetric resource. + properties: + default: + description: MeshMetric configuration. + properties: + applications: + description: Applications is a list of application that Dataplane + Proxy will scrape + items: + properties: + address: + description: Address on which an application listens. + type: string + name: + description: Name of the application to scrape + type: string + path: + default: /metrics/prometheus + description: Path on which an application expose HTTP endpoint + with metrics. + type: string + port: + description: Port on which an application expose HTTP endpoint + with metrics. + format: int32 + type: integer + required: + - port + type: object + type: array + backends: + description: Backends list that will be used to collect metrics. + items: + properties: + openTelemetry: + description: OpenTelemetry backend configuration + properties: + endpoint: + description: Endpoint for OpenTelemetry collector + type: string + refreshInterval: + description: RefreshInterval defines how frequent metrics + should be pushed to collector + type: string + required: + - endpoint + type: object + prometheus: + description: Prometheus backend configuration. + properties: + clientId: + description: ClientId of the Prometheus backend. Needed + when using MADS for DP discovery. + type: string + path: + default: /metrics + description: Path on which a dataplane should expose + HTTP endpoint with Prometheus metrics. + type: string + port: + default: 5670 + description: Port on which a dataplane should expose + HTTP endpoint with Prometheus metrics. + format: int32 + type: integer + tls: + description: Configuration of TLS for prometheus listener. + properties: + mode: + default: Disabled + description: Configuration of TLS for Prometheus + listener. + enum: + - Disabled + - ProvidedTLS + - ActiveMTLSBackend + type: string + required: + - mode + type: object + required: + - path + - port + type: object + type: + description: Type of the backend that will be used to collect + metrics. At the moment only Prometheus backend is available. + enum: + - Prometheus + - OpenTelemetry + type: string + required: + - type + type: object + type: array + sidecar: + description: Sidecar metrics collection configuration + properties: + includeUnused: + default: false + description: |- + IncludeUnused if false will scrape only metrics that has been by sidecar (counters incremented + at least once, gauges changed at least once, and histograms added to at + least once). If true will scrape all metrics (even the ones with zeros). + type: boolean + profiles: + description: Profiles allows to customize which metrics are + published. + properties: + appendProfiles: + description: AppendProfiles allows to combine the metrics + from multiple predefined profiles. + items: + properties: + name: + description: 'Name of the predefined profile, one + of: all, basic, none' + enum: + - All + - Basic + - None + type: string + required: + - name + type: object + type: array + exclude: + description: |- + Exclude makes it possible to exclude groups of metrics from a resulting profile. + Exclude is subordinate to Include. + items: + properties: + match: + description: Match is the value used to match using + particular Type + type: string + type: + description: 'Type defined the type of selector, + one of: prefix, regex, exact' + enum: + - Prefix + - Regex + - Exact + - Contains + type: string + required: + - match + - type + type: object + type: array + include: + description: |- + Include makes it possible to include additional metrics in a selected profiles. + Include takes precedence over Exclude. + items: + properties: + match: + description: Match is the value used to match using + particular Type + type: string + type: + description: 'Type defined the type of selector, + one of: prefix, regex, exact' + enum: + - Prefix + - Regex + - Exact + - Contains + type: string + required: + - match + - type + type: object + type: array + type: object + type: object + type: object + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined in-place. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshpassthroughs.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshpassthroughs.yaml new file mode 100644 index 000000000..aaa17e47e --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshpassthroughs.yaml @@ -0,0 +1,167 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshpassthroughs.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshPassthrough + listKind: MeshPassthroughList + plural: meshpassthroughs + singular: meshpassthrough + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshPassthrough resource. + properties: + default: + description: MeshPassthrough configuration. + properties: + appendMatch: + description: AppendMatch is a list of destinations that should + be allowed through the sidecar. + items: + properties: + port: + description: Port defines the port to which a user makes + a request. + type: integer + protocol: + default: tcp + description: 'Protocol defines the communication protocol. + Possible values: `tcp`, `tls`, `grpc`, `http`, `http2`.' + enum: + - tcp + - tls + - grpc + - http + - http2 + type: string + type: + description: Type of the match, one of `Domain`, `IP` or + `CIDR` is available. + enum: + - Domain + - IP + - CIDR + type: string + value: + description: Value for the specified Type. + type: string + required: + - port + type: object + type: array + passthroughMode: + default: None + description: |- + Defines the passthrough behavior. Possible values: `All`, `None`, `Matched` + When `All` or `None` `appendMatch` has no effect. + enum: + - All + - Matched + - None + type: string + type: object + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined in-place. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshproxypatches.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshproxypatches.yaml new file mode 100644 index 000000000..76daf5a47 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshproxypatches.yaml @@ -0,0 +1,560 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshproxypatches.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshProxyPatch + listKind: MeshProxyPatchList + plural: meshproxypatches + singular: meshproxypatch + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshProxyPatch resource. + properties: + default: + description: |- + Default is a configuration specific to the group of destinations + referenced in 'targetRef'. + properties: + appendModifications: + description: AppendModifications is a list of modifications applied + on the selected proxy. + items: + properties: + cluster: + description: Cluster is a modification of Envoy's Cluster + resource. + properties: + jsonPatches: + description: |- + JsonPatches specifies list of jsonpatches to apply to on Envoy's Cluster + resource + items: + description: JsonPatchBlock is one json patch operation + block. + properties: + from: + description: From is a jsonpatch from string, + used by move and copy operations. + type: string + op: + description: Op is a jsonpatch operation string. + enum: + - add + - remove + - replace + - move + - copy + type: string + path: + description: Path is a jsonpatch path string. + type: string + value: + description: Value must be a valid json value + used by replace and add operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + match: + description: Match is a set of conditions that have + to be matched for modification operation to happen. + properties: + name: + description: Name of the cluster to match. + type: string + origin: + description: |- + Origin is the name of the component or plugin that generated the resource. + + + Here is the list of well-known origins: + inbound - resources generated for handling incoming traffic. + outbound - resources generated for handling outgoing traffic. + transparent - resources generated for transparent proxy functionality. + prometheus - resources generated when Prometheus metrics are enabled. + direct-access - resources generated for Direct Access functionality. + ingress - resources generated for Zone Ingress. + egress - resources generated for Zone Egress. + gateway - resources generated for MeshGateway. + + + The list is not complete, because policy plugins can introduce new resources. + For example MeshTrace plugin can create Cluster with "mesh-trace" origin. + type: string + type: object + operation: + description: Operation to execute on matched cluster. + enum: + - Add + - Remove + - Patch + type: string + value: + description: Value of xDS resource in YAML format to + add or patch. + type: string + required: + - operation + type: object + httpFilter: + description: |- + HTTPFilter is a modification of Envoy HTTP Filter + available in HTTP Connection Manager in a Listener resource. + properties: + jsonPatches: + description: |- + JsonPatches specifies list of jsonpatches to apply to on Envoy's + HTTP Filter available in HTTP Connection Manager in a Listener resource. + items: + description: JsonPatchBlock is one json patch operation + block. + properties: + from: + description: From is a jsonpatch from string, + used by move and copy operations. + type: string + op: + description: Op is a jsonpatch operation string. + enum: + - add + - remove + - replace + - move + - copy + type: string + path: + description: Path is a jsonpatch path string. + type: string + value: + description: Value must be a valid json value + used by replace and add operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + match: + description: Match is a set of conditions that have + to be matched for modification operation to happen. + properties: + listenerName: + description: Name of the listener to match. + type: string + listenerTags: + additionalProperties: + type: string + description: Listener tags available in Listener#Metadata#FilterMetadata[io.kuma.tags] + type: object + name: + description: Name of the HTTP filter. For example + "envoy.filters.http.local_ratelimit" + type: string + origin: + description: |- + Origin is the name of the component or plugin that generated the resource. + + + Here is the list of well-known origins: + inbound - resources generated for handling incoming traffic. + outbound - resources generated for handling outgoing traffic. + transparent - resources generated for transparent proxy functionality. + prometheus - resources generated when Prometheus metrics are enabled. + direct-access - resources generated for Direct Access functionality. + ingress - resources generated for Zone Ingress. + egress - resources generated for Zone Egress. + gateway - resources generated for MeshGateway. + + + The list is not complete, because policy plugins can introduce new resources. + For example MeshTrace plugin can create Cluster with "mesh-trace" origin. + type: string + type: object + operation: + description: Operation to execute on matched listener. + enum: + - Remove + - Patch + - AddFirst + - AddBefore + - AddAfter + - AddLast + type: string + value: + description: Value of xDS resource in YAML format to + add or patch. + type: string + required: + - operation + type: object + listener: + description: Listener is a modification of Envoy's Listener + resource. + properties: + jsonPatches: + description: |- + JsonPatches specifies list of jsonpatches to apply to on Envoy's Listener + resource + items: + description: JsonPatchBlock is one json patch operation + block. + properties: + from: + description: From is a jsonpatch from string, + used by move and copy operations. + type: string + op: + description: Op is a jsonpatch operation string. + enum: + - add + - remove + - replace + - move + - copy + type: string + path: + description: Path is a jsonpatch path string. + type: string + value: + description: Value must be a valid json value + used by replace and add operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + match: + description: Match is a set of conditions that have + to be matched for modification operation to happen. + properties: + name: + description: Name of the listener to match. + type: string + origin: + description: |- + Origin is the name of the component or plugin that generated the resource. + + + Here is the list of well-known origins: + inbound - resources generated for handling incoming traffic. + outbound - resources generated for handling outgoing traffic. + transparent - resources generated for transparent proxy functionality. + prometheus - resources generated when Prometheus metrics are enabled. + direct-access - resources generated for Direct Access functionality. + ingress - resources generated for Zone Ingress. + egress - resources generated for Zone Egress. + gateway - resources generated for MeshGateway. + + + The list is not complete, because policy plugins can introduce new resources. + For example MeshTrace plugin can create Cluster with "mesh-trace" origin. + type: string + tags: + additionalProperties: + type: string + description: Tags available in Listener#Metadata#FilterMetadata[io.kuma.tags] + type: object + type: object + operation: + description: Operation to execute on matched listener. + enum: + - Add + - Remove + - Patch + type: string + value: + description: Value of xDS resource in YAML format to + add or patch. + type: string + required: + - operation + type: object + networkFilter: + description: NetworkFilter is a modification of Envoy Listener's + filter. + properties: + jsonPatches: + description: |- + JsonPatches specifies list of jsonpatches to apply to on Envoy Listener's + filter. + items: + description: JsonPatchBlock is one json patch operation + block. + properties: + from: + description: From is a jsonpatch from string, + used by move and copy operations. + type: string + op: + description: Op is a jsonpatch operation string. + enum: + - add + - remove + - replace + - move + - copy + type: string + path: + description: Path is a jsonpatch path string. + type: string + value: + description: Value must be a valid json value + used by replace and add operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + match: + description: Match is a set of conditions that have + to be matched for modification operation to happen. + properties: + listenerName: + description: Name of the listener to match. + type: string + listenerTags: + additionalProperties: + type: string + description: Listener tags available in Listener#Metadata#FilterMetadata[io.kuma.tags] + type: object + name: + description: Name of the network filter. For example + "envoy.filters.network.ratelimit" + type: string + origin: + description: |- + Origin is the name of the component or plugin that generated the resource. + + + Here is the list of well-known origins: + inbound - resources generated for handling incoming traffic. + outbound - resources generated for handling outgoing traffic. + transparent - resources generated for transparent proxy functionality. + prometheus - resources generated when Prometheus metrics are enabled. + direct-access - resources generated for Direct Access functionality. + ingress - resources generated for Zone Ingress. + egress - resources generated for Zone Egress. + gateway - resources generated for MeshGateway. + + + The list is not complete, because policy plugins can introduce new resources. + For example MeshTrace plugin can create Cluster with "mesh-trace" origin. + type: string + type: object + operation: + description: Operation to execute on matched listener. + enum: + - Remove + - Patch + - AddFirst + - AddBefore + - AddAfter + - AddLast + type: string + value: + description: Value of xDS resource in YAML format to + add or patch. + type: string + required: + - operation + type: object + virtualHost: + description: |- + VirtualHost is a modification of Envoy's VirtualHost + referenced in HTTP Connection Manager in a Listener resource. + properties: + jsonPatches: + description: |- + JsonPatches specifies list of jsonpatches to apply to on Envoy's + VirtualHost resource + items: + description: JsonPatchBlock is one json patch operation + block. + properties: + from: + description: From is a jsonpatch from string, + used by move and copy operations. + type: string + op: + description: Op is a jsonpatch operation string. + enum: + - add + - remove + - replace + - move + - copy + type: string + path: + description: Path is a jsonpatch path string. + type: string + value: + description: Value must be a valid json value + used by replace and add operations. + x-kubernetes-preserve-unknown-fields: true + required: + - op + - path + type: object + type: array + match: + description: Match is a set of conditions that have + to be matched for modification operation to happen. + properties: + name: + description: Name of the VirtualHost to match. + type: string + origin: + description: |- + Origin is the name of the component or plugin that generated the resource. + + + Here is the list of well-known origins: + inbound - resources generated for handling incoming traffic. + outbound - resources generated for handling outgoing traffic. + transparent - resources generated for transparent proxy functionality. + prometheus - resources generated when Prometheus metrics are enabled. + direct-access - resources generated for Direct Access functionality. + ingress - resources generated for Zone Ingress. + egress - resources generated for Zone Egress. + gateway - resources generated for MeshGateway. + + + The list is not complete, because policy plugins can introduce new resources. + For example MeshTrace plugin can create Cluster with "mesh-trace" origin. + type: string + routeConfigurationName: + description: Name of the RouteConfiguration resource + to match. + type: string + type: object + operation: + description: Operation to execute on matched listener. + enum: + - Add + - Remove + - Patch + type: string + value: + description: Value of xDS resource in YAML format to + add or patch. + type: string + required: + - match + - operation + type: object + type: object + type: array + required: + - appendModifications + type: object + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - default + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshratelimits.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshratelimits.yaml new file mode 100644 index 000000000..844d9c52f --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshratelimits.yaml @@ -0,0 +1,498 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshratelimits.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshRateLimit + listKind: MeshRateLimitList + plural: meshratelimits + singular: meshratelimit + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshRateLimit resource. + properties: + from: + description: From list makes a match between clients and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of clients referenced in + 'targetRef' + properties: + local: + description: LocalConf defines local http or/and tcp rate + limit configuration + properties: + http: + description: |- + LocalHTTP defines configuration of local HTTP rate limiting + https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/local_rate_limit_filter + properties: + disabled: + description: Define if rate limiting should be disabled. + type: boolean + onRateLimit: + description: Describes the actions to take on a + rate limit event + properties: + headers: + description: The Headers to be added to the + HTTP response on a rate limit event + properties: + add: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + set: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + status: + description: The HTTP status code to be set + on a rate limit event + format: int32 + type: integer + type: object + requestRate: + description: Defines how many requests are allowed + per interval. + properties: + interval: + description: The interval the number of units + is accounted for. + type: string + num: + description: |- + Number of units per interval (depending on usage it can be a number of requests, + or a number of connections). + format: int32 + type: integer + required: + - interval + - num + type: object + type: object + tcp: + description: |- + LocalTCP defines confguration of local TCP rate limiting + https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/local_rate_limit_filter + properties: + connectionRate: + description: Defines how many connections are allowed + per interval. + properties: + interval: + description: The interval the number of units + is accounted for. + type: string + num: + description: |- + Number of units per interval (depending on usage it can be a number of requests, + or a number of connections). + format: int32 + type: integer + required: + - interval + - num + type: object + disabled: + description: |- + Define if rate limiting should be disabled. + Default: false + type: boolean + type: object + type: object + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + clients. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: To list makes a match between clients and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of clients referenced in + 'targetRef' + properties: + local: + description: LocalConf defines local http or/and tcp rate + limit configuration + properties: + http: + description: |- + LocalHTTP defines configuration of local HTTP rate limiting + https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/local_rate_limit_filter + properties: + disabled: + description: Define if rate limiting should be disabled. + type: boolean + onRateLimit: + description: Describes the actions to take on a + rate limit event + properties: + headers: + description: The Headers to be added to the + HTTP response on a rate limit event + properties: + add: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + set: + items: + properties: + name: + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + status: + description: The HTTP status code to be set + on a rate limit event + format: int32 + type: integer + type: object + requestRate: + description: Defines how many requests are allowed + per interval. + properties: + interval: + description: The interval the number of units + is accounted for. + type: string + num: + description: |- + Number of units per interval (depending on usage it can be a number of requests, + or a number of connections). + format: int32 + type: integer + required: + - interval + - num + type: object + type: object + tcp: + description: |- + LocalTCP defines confguration of local TCP rate limiting + https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/local_rate_limit_filter + properties: + connectionRate: + description: Defines how many connections are allowed + per interval. + properties: + interval: + description: The interval the number of units + is accounted for. + type: string + num: + description: |- + Number of units per interval (depending on usage it can be a number of requests, + or a number of connections). + format: int32 + type: integer + required: + - interval + - num + type: object + disabled: + description: |- + Define if rate limiting should be disabled. + Default: false + type: boolean + type: object + type: object + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + clients. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshretries.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshretries.yaml new file mode 100644 index 000000000..404c0b2e5 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshretries.yaml @@ -0,0 +1,507 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshretries.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshRetry + listKind: MeshRetryList + plural: meshretries + singular: meshretry + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshRetry resource. + properties: + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: To list makes a match between the consumed services and + corresponding configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations referenced in + 'targetRef' + properties: + grpc: + description: GRPC defines a configuration of retries for + GRPC traffic + properties: + backOff: + description: |- + BackOff is a configuration of durations which will be used in an exponential + backoff strategy between retries. + properties: + baseInterval: + default: 25ms + description: |- + BaseInterval is an amount of time which should be taken between retries. + Must be greater than zero. Values less than 1 ms are rounded up to 1 ms. + type: string + maxInterval: + description: |- + MaxInterval is a maximal amount of time which will be taken between retries. + Default is 10 times the "BaseInterval". + type: string + type: object + numRetries: + description: |- + NumRetries is the number of attempts that will be made on failed (and + retriable) requests. If not set, the default value is 1. + format: int32 + type: integer + perTryTimeout: + description: |- + PerTryTimeout is the maximum amount of time each retry attempt can take + before it times out. If not set, the global request timeout for the route + will be used. Setting this value to 0 will disable the per-try timeout. + type: string + rateLimitedBackOff: + description: |- + RateLimitedBackOff is a configuration of backoff which will be used when + the upstream returns one of the headers configured. + properties: + maxInterval: + default: 300s + description: MaxInterval is a maximal amount of + time which will be taken between retries. + type: string + resetHeaders: + description: |- + ResetHeaders specifies the list of headers (like Retry-After or X-RateLimit-Reset) + to match against the response. Headers are tried in order, and matched + case-insensitive. The first header to be parsed successfully is used. + If no headers match the default exponential BackOff is used instead. + items: + properties: + format: + description: The format of the reset header. + enum: + - Seconds + - UnixTimestamp + type: string + name: + description: The Name of the reset header. + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + required: + - format + - name + type: object + type: array + type: object + retryOn: + description: RetryOn is a list of conditions which will + cause a retry. + example: + - Canceled + - DeadlineExceeded + - Internal + - ResourceExhausted + - Unavailable + items: + enum: + - Canceled + - DeadlineExceeded + - Internal + - ResourceExhausted + - Unavailable + type: string + type: array + type: object + http: + description: HTTP defines a configuration of retries for + HTTP traffic + properties: + backOff: + description: |- + BackOff is a configuration of durations which will be used in exponential + backoff strategy between retries. + properties: + baseInterval: + default: 25ms + description: |- + BaseInterval is an amount of time which should be taken between retries. + Must be greater than zero. Values less than 1 ms are rounded up to 1 ms. + type: string + maxInterval: + description: |- + MaxInterval is a maximal amount of time which will be taken between retries. + Default is 10 times the "BaseInterval". + type: string + type: object + hostSelection: + description: |- + HostSelection is a list of predicates that dictate how hosts should be selected + when requests are retried. + items: + properties: + predicate: + description: Type is requested predicate mode. + enum: + - OmitPreviousHosts + - OmitHostsWithTags + - OmitPreviousPriorities + type: string + tags: + additionalProperties: + type: string + description: |- + Tags is a map of metadata to match against for selecting the omitted hosts. Required if Type is + OmitHostsWithTags + type: object + updateFrequency: + default: 2 + description: |- + UpdateFrequency is how often the priority load should be updated based on previously attempted priorities. + Used for OmitPreviousPriorities. + format: int32 + type: integer + required: + - predicate + type: object + type: array + hostSelectionMaxAttempts: + description: |- + HostSelectionMaxAttempts is the maximum number of times host selection will be + reattempted before giving up, at which point the host that was last selected will + be routed to. If unspecified, this will default to retrying once. + format: int64 + type: integer + numRetries: + description: |- + NumRetries is the number of attempts that will be made on failed (and + retriable) requests. If not set, the default value is 1. + format: int32 + type: integer + perTryTimeout: + description: |- + PerTryTimeout is the amount of time after which retry attempt should time out. + If left unspecified, the global route timeout for the request will be used. + Consequently, when using a 5xx based retry policy, a request that times out + will not be retried as the total timeout budget would have been exhausted. + Setting this timeout to 0 will disable it. + type: string + rateLimitedBackOff: + description: |- + RateLimitedBackOff is a configuration of backoff which will be used + when the upstream returns one of the headers configured. + properties: + maxInterval: + default: 300s + description: MaxInterval is a maximal amount of + time which will be taken between retries. + type: string + resetHeaders: + description: |- + ResetHeaders specifies the list of headers (like Retry-After or X-RateLimit-Reset) + to match against the response. Headers are tried in order, and matched + case-insensitive. The first header to be parsed successfully is used. + If no headers match the default exponential BackOff is used instead. + items: + properties: + format: + description: The format of the reset header. + enum: + - Seconds + - UnixTimestamp + type: string + name: + description: The Name of the reset header. + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + required: + - format + - name + type: object + type: array + type: object + retriableRequestHeaders: + description: |- + RetriableRequestHeaders is an HTTP headers which must be present in the request + for retries to be attempted. + items: + description: |- + HeaderMatch describes how to select an HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name MUST be lower case + as they will be handled with case insensitivity (See https://tools.ietf.org/html/rfc7230#section-3.2). + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: Type specifies how to match against + the value of the header. + enum: + - Exact + - Present + - RegularExpression + - Absent + - Prefix + type: string + value: + description: Value is the value of HTTP Header + to be matched. + type: string + required: + - name + type: object + type: array + retriableResponseHeaders: + description: |- + RetriableResponseHeaders is an HTTP response headers that trigger a retry + if present in the response. A retry will be triggered if any of the header + matches the upstream response headers. + items: + description: |- + HeaderMatch describes how to select an HTTP route by matching HTTP request + headers. + properties: + name: + description: |- + Name is the name of the HTTP Header to be matched. Name MUST be lower case + as they will be handled with case insensitivity (See https://tools.ietf.org/html/rfc7230#section-3.2). + maxLength: 256 + minLength: 1 + pattern: ^[a-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: Type specifies how to match against + the value of the header. + enum: + - Exact + - Present + - RegularExpression + - Absent + - Prefix + type: string + value: + description: Value is the value of HTTP Header + to be matched. + type: string + required: + - name + type: object + type: array + retryOn: + description: |- + RetryOn is a list of conditions which will cause a retry. Available values are: + [5XX, GatewayError, Reset, Retriable4xx, ConnectFailure, EnvoyRatelimited, + RefusedStream, Http3PostConnectFailure, HttpMethodConnect, HttpMethodDelete, + HttpMethodGet, HttpMethodHead, HttpMethodOptions, HttpMethodPatch, + HttpMethodPost, HttpMethodPut, HttpMethodTrace]. + Also, any HTTP status code (500, 503, etc.). + example: + - 5XX + - GatewayError + - Reset + - Retriable4xx + - ConnectFailure + - EnvoyRatelimited + - RefusedStream + - Http3PostConnectFailure + - HttpMethodConnect + - HttpMethodDelete + - HttpMethodGet + - HttpMethodHead + - HttpMethodOptions + - HttpMethodPatch + - HttpMethodPost + - HttpMethodPut + - HttpMethodTrace + - "500" + - "503" + items: + type: string + type: array + type: object + tcp: + description: TCP defines a configuration of retries for + TCP traffic + properties: + maxConnectAttempt: + description: |- + MaxConnectAttempt is a maximal amount of TCP connection attempts + which will be made before giving up + format: int32 + type: integer + type: object + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshservices.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshservices.yaml new file mode 100644 index 000000000..c4548da4e --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshservices.yaml @@ -0,0 +1,195 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshservices.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshService + listKind: MeshServiceList + plural: meshservices + singular: meshservice + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshService resource. + properties: + identities: + items: + properties: + type: + enum: + - ServiceTag + type: string + value: + type: string + required: + - type + - value + type: object + type: array + ports: + items: + properties: + appProtocol: + default: tcp + description: Protocol identifies a protocol supported by a service. + type: string + name: + type: string + port: + format: int32 + type: integer + targetPort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: array + x-kubernetes-list-map-keys: + - port + - appProtocol + x-kubernetes-list-type: map + selector: + properties: + dataplaneRef: + properties: + name: + type: string + type: object + dataplaneTags: + additionalProperties: + type: string + type: object + type: object + type: object + status: + description: Status is the current status of the Kuma MeshService resource. + properties: + addresses: + items: + properties: + hostname: + type: string + hostnameGeneratorRef: + properties: + coreName: + type: string + required: + - coreName + type: object + origin: + type: string + type: object + type: array + hostnameGenerators: + items: + properties: + conditions: + description: Conditions is an array of hostname generator conditions. + items: + properties: + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + hostnameGeneratorRef: + properties: + coreName: + type: string + required: + - coreName + type: object + required: + - hostnameGeneratorRef + type: object + type: array + tls: + properties: + status: + enum: + - Ready + - NotReady + type: string + type: object + vips: + items: + properties: + ip: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtcproutes.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtcproutes.yaml new file mode 100644 index 000000000..5ba894de8 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtcproutes.yaml @@ -0,0 +1,281 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshtcproutes.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshTCPRoute + listKind: MeshTCPRouteList + plural: meshtcproutes + singular: meshtcproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshTCPRoute resource. + properties: + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined in-place. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: |- + To list makes a match between the consumed services and corresponding + configurations + items: + properties: + rules: + description: |- + Rules contains the routing rules applies to a combination of top-level + targetRef and the targetRef in this entry. + items: + properties: + default: + description: |- + Default holds routing rules that can be merged with rules from other + policies. + properties: + backendRefs: + items: + description: BackendRef defines where to forward + traffic. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use + to identify cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + port: + description: Port is only supported when this + ref refers to a real MeshService object + format: int32 + type: integer + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + weight: + default: 1 + minimum: 0 + type: integer + type: object + minItems: 1 + type: array + required: + - backendRefs + type: object + required: + - default + type: object + maxItems: 1 + type: array + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + minItems: 1 + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtimeouts.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtimeouts.yaml new file mode 100644 index 000000000..f8a7205eb --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtimeouts.yaml @@ -0,0 +1,362 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshtimeouts.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshTimeout + listKind: MeshTimeoutList + plural: meshtimeouts + singular: meshtimeout + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshTimeout resource. + properties: + from: + description: From list makes a match between clients and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of clients referenced in + 'targetRef' + properties: + connectionTimeout: + description: |- + ConnectionTimeout specifies the amount of time proxy will wait for an TCP connection to be established. + Default value is 5 seconds. Cannot be set to 0. + type: string + http: + description: Http provides configuration for HTTP specific + timeouts + properties: + maxConnectionDuration: + description: |- + MaxConnectionDuration is the time after which a connection will be drained and/or closed, + starting from when it was first established. Setting this timeout to 0 will disable it. + Disabled by default. + type: string + maxStreamDuration: + description: |- + MaxStreamDuration is the maximum time that a stream’s lifetime will span. + Setting this timeout to 0 will disable it. Disabled by default. + type: string + requestHeadersTimeout: + description: |- + RequestHeadersTimeout The amount of time that proxy will wait for the request headers to be received. The timer is + activated when the first byte of the headers is received, and is disarmed when the last byte of + the headers has been received. If not specified or set to 0, this timeout is disabled. + Disabled by default. + type: string + requestTimeout: + description: |- + RequestTimeout The amount of time that proxy will wait for the entire request to be received. + The timer is activated when the request is initiated, and is disarmed when the last byte of the request is sent, + OR when the response is initiated. Setting this timeout to 0 will disable it. + Default is 15s. + type: string + streamIdleTimeout: + description: |- + StreamIdleTimeout is the amount of time that proxy will allow a stream to exist with no activity. + Setting this timeout to 0 will disable it. Default is 30m + type: string + type: object + idleTimeout: + description: |- + IdleTimeout is defined as the period in which there are no bytes sent or received on connection + Setting this timeout to 0 will disable it. Be cautious when disabling it because + it can lead to connection leaking. Default value is 1h. + type: string + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + clients. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + to: + description: To list makes a match between the consumed services and + corresponding configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of destinations referenced in + 'targetRef' + properties: + connectionTimeout: + description: |- + ConnectionTimeout specifies the amount of time proxy will wait for an TCP connection to be established. + Default value is 5 seconds. Cannot be set to 0. + type: string + http: + description: Http provides configuration for HTTP specific + timeouts + properties: + maxConnectionDuration: + description: |- + MaxConnectionDuration is the time after which a connection will be drained and/or closed, + starting from when it was first established. Setting this timeout to 0 will disable it. + Disabled by default. + type: string + maxStreamDuration: + description: |- + MaxStreamDuration is the maximum time that a stream’s lifetime will span. + Setting this timeout to 0 will disable it. Disabled by default. + type: string + requestHeadersTimeout: + description: |- + RequestHeadersTimeout The amount of time that proxy will wait for the request headers to be received. The timer is + activated when the first byte of the headers is received, and is disarmed when the last byte of + the headers has been received. If not specified or set to 0, this timeout is disabled. + Disabled by default. + type: string + requestTimeout: + description: |- + RequestTimeout The amount of time that proxy will wait for the entire request to be received. + The timer is activated when the request is initiated, and is disarmed when the last byte of the request is sent, + OR when the response is initiated. Setting this timeout to 0 will disable it. + Default is 15s. + type: string + streamIdleTimeout: + description: |- + StreamIdleTimeout is the amount of time that proxy will allow a stream to exist with no activity. + Setting this timeout to 0 will disable it. Default is 30m + type: string + type: object + idleTimeout: + description: |- + IdleTimeout is defined as the period in which there are no bytes sent or received on connection + Setting this timeout to 0 will disable it. Be cautious when disabling it because + it can lead to connection leaking. Default value is 1h. + type: string + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + destinations. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtraces.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtraces.yaml new file mode 100644 index 000000000..2107140d3 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtraces.yaml @@ -0,0 +1,284 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshtraces.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshTrace + listKind: MeshTraceList + plural: meshtraces + singular: meshtrace + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshTrace resource. + properties: + default: + description: MeshTrace configuration. + properties: + backends: + description: |- + A one element array of backend definition. + Envoy allows configuring only 1 backend, so the natural way of + representing that would be just one object. Unfortunately due to the + reasons explained in MADR 009-tracing-policy this has to be a one element + array for now. + items: + description: Only one of zipkin, datadog or openTelemetry can + be used. + properties: + datadog: + description: Datadog backend configuration. + properties: + splitService: + default: false + description: |- + Determines if datadog service name should be split based on traffic + direction and destination. For example, with `splitService: true` and a + `backend` service that communicates with a couple of databases, you would + get service names like `backend_INBOUND`, `backend_OUTBOUND_db1`, and + `backend_OUTBOUND_db2` in Datadog. + type: boolean + url: + description: |- + Address of Datadog collector, only host and port are allowed (no paths, + fragments etc.) + type: string + required: + - url + type: object + openTelemetry: + description: OpenTelemetry backend configuration. + properties: + endpoint: + description: Address of OpenTelemetry collector. + example: otel-collector:4317 + minLength: 1 + type: string + required: + - endpoint + type: object + type: + enum: + - Zipkin + - Datadog + - OpenTelemetry + type: string + zipkin: + description: Zipkin backend configuration. + properties: + apiVersion: + default: httpJson + description: |- + Version of the API. + https://github.com/envoyproxy/envoy/blob/v1.22.0/api/envoy/config/trace/v3/zipkin.proto#L66 + enum: + - httpJson + - httpProto + type: string + sharedSpanContext: + default: true + description: |- + Determines whether client and server spans will share the same span + context. + https://github.com/envoyproxy/envoy/blob/v1.22.0/api/envoy/config/trace/v3/zipkin.proto#L63 + type: boolean + traceId128bit: + default: false + description: Generate 128bit traces. + type: boolean + url: + description: Address of Zipkin collector. + type: string + required: + - url + type: object + required: + - type + type: object + maxItems: 1 + type: array + sampling: + description: |- + Sampling configuration. + Sampling is the process by which a decision is made on whether to + process/export a span or not. + properties: + client: + anyOf: + - type: integer + - type: string + default: 100% + description: |- + Target percentage of requests that will be force traced if the + 'x-client-trace-id' header is set. Mirror of client_sampling in Envoy + https://github.com/envoyproxy/envoy/blob/v1.22.0/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto#L127-L133 + Either int or decimal represented as string. + x-kubernetes-int-or-string: true + overall: + anyOf: + - type: integer + - type: string + default: 100% + description: |- + Target percentage of requests will be traced + after all other sampling checks have been applied (client, force tracing, + random sampling). This field functions as an upper limit on the total + configured sampling rate. For instance, setting client_sampling to 100% + but overall_sampling to 1% will result in only 1% of client requests with + the appropriate headers to be force traced. Mirror of + overall_sampling in Envoy + https://github.com/envoyproxy/envoy/blob/v1.22.0/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto#L142-L150 + Either int or decimal represented as string. + x-kubernetes-int-or-string: true + random: + anyOf: + - type: integer + - type: string + default: 100% + description: |- + Target percentage of requests that will be randomly selected for trace + generation, if not requested by the client or not forced. + Mirror of random_sampling in Envoy + https://github.com/envoyproxy/envoy/blob/v1.22.0/api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto#L135-L140 + Either int or decimal represented as string. + x-kubernetes-int-or-string: true + type: object + tags: + description: |- + Custom tags configuration. You can add custom tags to traces based on + headers or literal values. + items: + description: |- + Custom tags configuration. + Only one of literal or header can be used. + properties: + header: + description: Tag taken from a header. + properties: + default: + description: |- + Default value to use if header is missing. + If the default is missing and there is no value the tag will not be + included. + type: string + name: + description: Name of the header. + type: string + required: + - name + type: object + literal: + description: Tag taken from literal value. + type: string + name: + description: Name of the tag. + type: string + required: + - name + type: object + type: array + type: object + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtrafficpermissions.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtrafficpermissions.yaml new file mode 100644 index 000000000..05d433788 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_meshtrafficpermissions.yaml @@ -0,0 +1,203 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: meshtrafficpermissions.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: MeshTrafficPermission + listKind: MeshTrafficPermissionList + plural: meshtrafficpermissions + singular: meshtrafficpermission + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.targetRef.kind + name: TargetRef Kind + type: string + - jsonPath: .spec.targetRef.name + name: TargetRef Name + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma MeshTrafficPermission + resource. + properties: + from: + description: From list makes a match between clients and corresponding + configurations + items: + properties: + default: + description: |- + Default is a configuration specific to the group of clients referenced in + 'targetRef' + properties: + action: + description: 'Action defines a behavior for the specified + group of clients:' + enum: + - Allow + - Deny + - AllowWithShadowDeny + type: string + type: object + targetRef: + description: |- + TargetRef is a reference to the resource that represents a group of + clients. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify + cross mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: array + targetRef: + description: |- + TargetRef is a reference to the resource the policy takes an effect on. + The resource could be either a real store object or virtual resource + defined inplace. + properties: + kind: + description: Kind of the referenced resource + enum: + - Mesh + - MeshSubset + - MeshGateway + - MeshService + - MeshExternalService + - MeshServiceSubset + - MeshHTTPRoute + type: string + labels: + additionalProperties: + type: string + description: |- + Labels are used to select group of MeshServices that match labels. Either Labels or + Name and Namespace can be used. + type: object + mesh: + description: Mesh is reserved for future use to identify cross + mesh resources. + type: string + name: + description: |- + Name of the referenced resource. Can only be used with kinds: `MeshService`, + `MeshServiceSubset` and `MeshGatewayRoute` + type: string + namespace: + description: |- + Namespace specifies the namespace of target resource. If empty only resources in policy namespace + will be targeted. + type: string + proxyTypes: + description: |- + ProxyTypes specifies the data plane types that are subject to the policy. When not specified, + all data plane types are targeted by the policy. + items: + enum: + - Sidecar + - Gateway + type: string + minItems: 1 + type: array + sectionName: + description: |- + SectionName is used to target specific section of resource. + For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected. + type: string + tags: + additionalProperties: + type: string + description: |- + Tags used to select a subset of proxies by tags. Can only be used with kinds + `MeshSubset` and `MeshServiceSubset` + type: object + type: object + required: + - targetRef + type: object + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_proxytemplates.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_proxytemplates.yaml new file mode 100644 index 000000000..7d598fb0c --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_proxytemplates.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: proxytemplates.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ProxyTemplate + listKind: ProxyTemplateList + plural: proxytemplates + singular: proxytemplate + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma ProxyTemplate resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_ratelimits.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_ratelimits.yaml new file mode 100644 index 000000000..458280883 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_ratelimits.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: ratelimits.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: RateLimit + listKind: RateLimitList + plural: ratelimits + singular: ratelimit + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma RateLimit resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_retries.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_retries.yaml new file mode 100644 index 000000000..040efe058 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_retries.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: retries.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: Retry + listKind: RetryList + plural: retries + singular: retry + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma Retry resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_serviceinsights.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_serviceinsights.yaml new file mode 100644 index 000000000..69a4f709b --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_serviceinsights.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: serviceinsights.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ServiceInsight + listKind: ServiceInsightList + plural: serviceinsights + singular: serviceinsight + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma ServiceInsight resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_timeouts.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_timeouts.yaml new file mode 100644 index 000000000..659998990 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_timeouts.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: timeouts.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: Timeout + listKind: TimeoutList + plural: timeouts + singular: timeout + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma Timeout resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficlogs.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficlogs.yaml new file mode 100644 index 000000000..e299ef299 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficlogs.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: trafficlogs.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: TrafficLog + listKind: TrafficLogList + plural: trafficlogs + singular: trafficlog + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma TrafficLog resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficpermissions.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficpermissions.yaml new file mode 100644 index 000000000..087eecec1 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficpermissions.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: trafficpermissions.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: TrafficPermission + listKind: TrafficPermissionList + plural: trafficpermissions + singular: trafficpermission + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma TrafficPermission resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficroutes.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficroutes.yaml new file mode 100644 index 000000000..6fdb809cf --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_trafficroutes.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: trafficroutes.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: TrafficRoute + listKind: TrafficRouteList + plural: trafficroutes + singular: trafficroute + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma TrafficRoute resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_traffictraces.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_traffictraces.yaml new file mode 100644 index 000000000..7f9832df7 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_traffictraces.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: traffictraces.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: TrafficTrace + listKind: TrafficTraceList + plural: traffictraces + singular: traffictrace + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma TrafficTrace resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_virtualoutbounds.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_virtualoutbounds.yaml new file mode 100644 index 000000000..c158f29bd --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_virtualoutbounds.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: virtualoutbounds.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: VirtualOutbound + listKind: VirtualOutboundList + plural: virtualoutbounds + singular: virtualoutbound + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma VirtualOutbound resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneegresses.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneegresses.yaml new file mode 100644 index 000000000..2dbcea457 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneegresses.yaml @@ -0,0 +1,56 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: zoneegresses.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ZoneEgress + listKind: ZoneEgressList + plural: zoneegresses + singular: zoneegress + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Zone name + jsonPath: .spec.zone + name: zone + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma ZoneEgress resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneegressinsights.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneegressinsights.yaml new file mode 100644 index 000000000..58a995697 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneegressinsights.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: zoneegressinsights.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ZoneEgressInsight + listKind: ZoneEgressInsightList + plural: zoneegressinsights + singular: zoneegressinsight + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma ZoneEgressInsight resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneingresses.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneingresses.yaml new file mode 100644 index 000000000..8f3e83575 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneingresses.yaml @@ -0,0 +1,56 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: zoneingresses.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ZoneIngress + listKind: ZoneIngressList + plural: zoneingresses + singular: zoneingress + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Zone name + jsonPath: .spec.zone + name: zone + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma ZoneIngress resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: {} diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneingressinsights.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneingressinsights.yaml new file mode 100644 index 000000000..66a51ae5f --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneingressinsights.yaml @@ -0,0 +1,51 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: zoneingressinsights.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ZoneIngressInsight + listKind: ZoneIngressInsightList + plural: zoneingressinsights + singular: zoneingressinsight + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma ZoneIngressInsight + resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneinsights.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneinsights.yaml new file mode 100644 index 000000000..28e26eaf7 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_zoneinsights.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: zoneinsights.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: ZoneInsight + listKind: ZoneInsightList + plural: zoneinsights + singular: zoneinsight + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma ZoneInsight resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/crds/kuma.io_zones.yaml b/charts/kuma/kuma/2.8.2/crds/kuma.io_zones.yaml new file mode 100644 index 000000000..e750c6388 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/crds/kuma.io_zones.yaml @@ -0,0 +1,50 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: zones.kuma.io +spec: + group: kuma.io + names: + categories: + - kuma + kind: Zone + listKind: ZoneList + plural: zones + singular: zone + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + mesh: + description: |- + Mesh is the name of the Kuma mesh this resource belongs to. + It may be omitted for cluster-scoped resources. + type: string + metadata: + type: object + spec: + description: Spec is the specification of the Kuma Zone resource. + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true diff --git a/charts/kuma/kuma/2.8.2/templates/NOTES.txt b/charts/kuma/kuma/2.8.2/templates/NOTES.txt new file mode 100644 index 000000000..228ac26e7 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/NOTES.txt @@ -0,0 +1,42 @@ +{{ .Chart.Name }} has been installed! + +Your release is named '{{ .Release.Name }}'. + +You can access the control-plane via either the GUI, kubectl, the HTTP API, or the kumactl CLI. +{{- if .Values.noHelmHooks }} + +------------------------------------------------------------------------------- + + WARNING + + When the "noHelmHooks" value is provided, you will need to manually delete + the "ValidatingWebhookConfiguration" responsible for validating {{ include "kuma.name" . }} resources + before you can uninstall Helm release. This is because the validation provided + by the webhook is not necessary during the release removal and might potentially + even prevent you from doing it. You can do this by running the following command: + + kubectl delete ValidatingWebhookConfiguration {{ include "kuma.name" . }}-validating-webhook-configuration + + WARNING + + When the "noHelmHooks" value is set, Helm will not automatically update + the CustomResourceDefinitions (CRDs) when upgrading release. You must manually + update the CRDs if the new {{ include "kuma.name" . }} version has changes + to the CRDs. You can achieve this by calling the following command: + + kumactl install crds --no-config | kubectl apply -f + +{{- if and .Values.experimental.ebpf.enabled (not .Values.cni.enabled) }} + + WARNING + + When the "noHelmHooks" value is set, Helm will not automatically uninstall + the eBPF resources. You will need to manually uninstall these resources after + uninstalling Helm release. To do this, run the following command: + + kumactl uninstall ebpf --cleanup-image-registry {{ .Values.global.image.registry }} --cleanup-image-repository {{ .Values.dataPlane.initImage.repository }} + +{{- end }} + +------------------------------------------------------------------------------- +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/_helpers.tpl b/charts/kuma/kuma/2.8.2/templates/_helpers.tpl new file mode 100644 index 000000000..0627d36fa --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/_helpers.tpl @@ -0,0 +1,402 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "kuma.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +This is the Kuma version the chart is intended to be used with. +*/}} +{{- define "kuma.appVersion" -}} +{{- .Chart.AppVersion -}} +{{- end }} + +{{/* +This is only used in the `kuma.formatImage` function below. +*/}} +{{- define "kuma.defaultRegistry" -}} +docker.io/kumahq +{{- end }} + +{{- define "kuma.product" -}} +Kuma +{{- end }} + +{{- define "kuma.tagPrefix" -}} +{{- 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 "kuma.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 "kuma.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "kuma.controlPlane.serviceName" -}} +{{- $defaultSvcName := printf "%s-control-plane" (include "kuma.name" .) -}} +{{ printf "%s" (default $defaultSvcName .Values.controlPlane.service.name) }} +{{- end }} + +{{- define "kuma.controlPlane.globalZoneSync.serviceName" -}} +{{- $defaultSvcName := printf "%s-global-zone-sync" (include "kuma.name" .) -}} +{{ printf "%s" (default $defaultSvcName .Values.controlPlane.globalZoneSyncService.name) }} +{{- end }} + +{{- define "kuma.ingress.serviceName" -}} +{{- $defaultSvcName := printf "%s-ingress" (include "kuma.name" .) -}} +{{ printf "%s" (default $defaultSvcName .Values.ingress.service.name) }} +{{- end }} + +{{- define "kuma.egress.serviceName" -}} +{{- $defaultSvcName := printf "%s-egress" (include "kuma.name" .) -}} +{{ printf "%s" (default $defaultSvcName .Values.egress.service.name) }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "kuma.labels" -}} +helm.sh/chart: {{ include "kuma.chart" . }} +{{ include "kuma.selectorLabels" . }} +{{- if (include "kuma.appVersion" .) }} +app.kubernetes.io/version: {{ (include "kuma.appVersion" .) | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "kuma.selectorLabels" -}} +app.kubernetes.io/name: {{ include "kuma.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +CNI labels +*/}} +{{- define "kuma.cniLabels" -}} +app: {{ include "kuma.name" . }}-cni +{{ include "kuma.labels" . }} +{{- end }} + +{{/* +control plane labels +*/}} +{{- define "kuma.cpLabels" -}} +app: {{ include "kuma.name" . }}-control-plane +{{- range $key, $value := $.Values.controlPlane.extraLabels }} +{{ $key | quote }}: {{ $value | quote }} +{{- end }} +{{ include "kuma.labels" . }} +{{- end }} + +{{/* +control plane deployment annotations +*/}} +{{- define "kuma.cpDeploymentAnnotations" -}} +{{- range $key, $value := $.Values.controlPlane.deploymentAnnotations }} +{{ $key | quote }}: {{ $value | quote }} +{{- end }} +{{- end }} + +{{/* +ingress labels +*/}} +{{- define "kuma.ingressLabels" -}} +app: {{ include "kuma.name" . }}-ingress +{{- range $key, $value := .Values.ingress.extraLabels }} +{{ $key | quote }}: {{ $value | quote }} +{{- end }} +{{ include "kuma.labels" . }} +{{- end }} + +{{/* +egress labels +*/}} +{{- define "kuma.egressLabels" -}} +app: {{ include "kuma.name" . }}-egress +{{ range $key, $value := .Values.egress.extraLabels }} +{{ $key | quote }}: {{ $value | quote }} +{{ end }} +{{- include "kuma.labels" . }} +{{- end }} + +{{/* +CNI selector labels +*/}} +{{- define "kuma.cniSelectorLabels" -}} +app: {{ include "kuma.name" . }}-cni +{{ include "kuma.selectorLabels" . }} +{{- end }} + +{{/* +params: { image: { registry?, repository, tag? }, root: $ } +returns: formatted image string +*/}} +{{- define "kuma.formatImage" -}} +{{- $img := .image }} +{{- $root := .root }} +{{- $registry := ($img.registry | default $root.Values.global.image.registry) -}} +{{- $repo := ($img.repository | required "Must specify image repository") -}} +{{- $product := (include "kuma.product" .) }} +{{- $tagPrefix := (include "kuma.tagPrefix" .) }} +{{- $expectedVersion := (include "kuma.appVersion" $root) }} +{{- if + and + $root.Values.global.image.tag + (ne $root.Values.global.image.tag (include "kuma.appVersion" $root)) + (eq $root.Values.global.image.registry (include "kuma.defaultRegistry" .)) +-}} +{{- fail ( + printf "This chart only supports %s version %q but %sglobal.image.tag is set to %q. Set %sglobal.image.tag to %q or skip this check by setting %s*.image.tag for each individual component." + $product $expectedVersion $tagPrefix $root.Values.global.image.tag $tagPrefix $expectedVersion $tagPrefix +) -}} +{{- end -}} +{{- $defaultTag := ($root.Values.global.image.tag | default (include "kuma.appVersion" $root)) -}} +{{- $tag := ($img.tag | default $defaultTag) -}} +{{- printf "%s/%s:%s" $registry $repo $tag -}} +{{- end -}} + +{{- define "kuma.parentEnv" -}} +{{- end -}} + +{{- define "kuma.parentSecrets" -}} +{{- end -}} + +{{- define "kuma.pluginPoliciesEnabled" -}} +{{- $list := list -}} +{{- range $k, $v := .Values.plugins.policies -}} +{{- if $v -}} +{{- $list = append $list (printf "%s" $k) -}} +{{- end -}} +{{- end -}} +{{ join "," $list }} +{{- end -}} + +{{- define "kuma.defaultEnv" -}} +env: +{{ include "kuma.parentEnv" . }} +- name: KUMA_ENVIRONMENT + value: "kubernetes" +- name: KUMA_STORE_TYPE + value: "kubernetes" +- name: KUMA_STORE_KUBERNETES_SYSTEM_NAMESPACE + value: {{ .Release.Namespace | quote }} +- name: KUMA_RUNTIME_KUBERNETES_CONTROL_PLANE_SERVICE_NAME + value: {{ include "kuma.controlPlane.serviceName" . }} +- name: KUMA_GENERAL_TLS_CERT_FILE + value: /var/run/secrets/kuma.io/tls-cert/tls.crt +- name: KUMA_GENERAL_TLS_KEY_FILE + value: /var/run/secrets/kuma.io/tls-cert/tls.key +{{- if eq .Values.controlPlane.mode "zone" }} +- name: KUMA_MULTIZONE_ZONE_GLOBAL_ADDRESS + value: {{ .Values.controlPlane.kdsGlobalAddress }} +{{- end }} +- name: KUMA_DP_SERVER_HDS_ENABLED + value: "false" +- name: KUMA_API_SERVER_READ_ONLY + value: "true" +- name: KUMA_RUNTIME_KUBERNETES_ADMISSION_SERVER_PORT + value: {{ .Values.controlPlane.admissionServerPort | default "5443" | quote }} +- name: KUMA_RUNTIME_KUBERNETES_ADMISSION_SERVER_CERT_DIR + value: /var/run/secrets/kuma.io/tls-cert +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_CNI_ENABLED + value: {{ .Values.cni.enabled | quote }} +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_SIDECAR_CONTAINER_IMAGE + value: {{ include "kuma.formatImage" (dict "image" .Values.dataPlane.image "root" $) | quote }} +- name: KUMA_INJECTOR_INIT_CONTAINER_IMAGE + value: {{ include "kuma.formatImage" (dict "image" .Values.dataPlane.initImage "root" $) | quote }} +{{- if .Values.dataPlane.dnsLogging }} +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_BUILTIN_DNS_LOGGING + value: "true" +{{- end }} +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_CA_CERT_FILE + value: /var/run/secrets/kuma.io/tls-cert/ca.crt +- name: KUMA_DEFAULTS_SKIP_MESH_CREATION + value: {{ .Values.controlPlane.defaults.skipMeshCreation | quote }} +- name: KUMA_MODE + value: {{ .Values.controlPlane.mode | quote }} +{{- if .Values.controlPlane.zone }} +- name: KUMA_MULTIZONE_ZONE_NAME + value: {{ .Values.controlPlane.zone | quote }} +{{- end }} +{{- if .Values.controlPlane.tls.apiServer.secretName }} +- name: KUMA_API_SERVER_HTTPS_TLS_CERT_FILE + value: /var/run/secrets/kuma.io/api-server-tls-cert/tls.crt +- name: KUMA_API_SERVER_HTTPS_TLS_KEY_FILE + value: /var/run/secrets/kuma.io/api-server-tls-cert/tls.key +{{- end }} +{{- if .Values.controlPlane.tls.apiServer.clientCertsSecretName }} +- name: KUMA_API_SERVER_AUTH_CLIENT_CERTS_DIR + value: /var/run/secrets/kuma.io/api-server-client-certs/ +{{- end }} +{{- if and (eq .Values.controlPlane.mode "global") (or .Values.controlPlane.tls.kdsGlobalServer.secretName .Values.controlPlane.tls.kdsGlobalServer.create) }} +- name: KUMA_MULTIZONE_GLOBAL_KDS_TLS_CERT_FILE + value: /var/run/secrets/kuma.io/kds-server-tls-cert/tls.crt +- name: KUMA_MULTIZONE_GLOBAL_KDS_TLS_KEY_FILE + value: /var/run/secrets/kuma.io/kds-server-tls-cert/tls.key +{{- end }} +{{- if and (eq .Values.controlPlane.mode "zone") (or .Values.controlPlane.tls.kdsZoneClient.secretName .Values.controlPlane.tls.kdsZoneClient.create) }} +- name: KUMA_MULTIZONE_ZONE_KDS_ROOT_CA_FILE + value: /var/run/secrets/kuma.io/kds-client-tls-cert/ca.crt +{{- end }} +- name: KUMA_API_SERVER_AUTHN_LOCALHOST_IS_ADMIN + value: "false" +- name: KUMA_RUNTIME_KUBERNETES_ALLOWED_USERS + value: "system:serviceaccount:{{ .Release.Namespace }}:{{ include "kuma.name" . }}-control-plane" +{{- if .Values.experimental.sidecarContainers }} +- name: KUMA_EXPERIMENTAL_SIDECAR_CONTAINERS + value: "true" +{{- end }} +{{- if .Values.cni.enabled }} +- name: KUMA_RUNTIME_KUBERNETES_NODE_TAINT_CONTROLLER_ENABLED + value: "true" +- name: KUMA_RUNTIME_KUBERNETES_NODE_TAINT_CONTROLLER_CNI_APP + value: "{{ include "kuma.name" . }}-cni" +- name: KUMA_RUNTIME_KUBERNETES_NODE_TAINT_CONTROLLER_CNI_NAMESPACE + value: {{ .Values.cni.namespace }} +{{- end }} +{{- if .Values.experimental.ebpf.enabled }} +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_EBPF_ENABLED + value: "true" +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_EBPF_INSTANCE_IP_ENV_VAR_NAME + value: {{ .Values.experimental.ebpf.instanceIPEnvVarName }} +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_EBPF_BPFFS_PATH + value: {{ .Values.experimental.ebpf.bpffsPath }} +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_EBPF_CGROUP_PATH + value: {{ .Values.experimental.ebpf.cgroupPath }} +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_EBPF_TC_ATTACH_IFACE + value: {{ .Values.experimental.ebpf.tcAttachIface }} +- name: KUMA_RUNTIME_KUBERNETES_INJECTOR_EBPF_PROGRAMS_SOURCE_PATH + value: {{ .Values.experimental.ebpf.programsSourcePath }} +{{- end }} +{{- if not .Values.experimental.deltaKds }} +- name: KUMA_EXPERIMENTAL_KDS_DELTA_ENABLED + value: "false" +{{- end }} +{{- if .Values.controlPlane.tls.kdsZoneClient.skipVerify }} +- name: KUMA_MULTIZONE_ZONE_KDS_TLS_SKIP_VERIFY + value: "true" +{{- end }} +- name: KUMA_PLUGIN_POLICIES_ENABLED + value: {{ include "kuma.pluginPoliciesEnabled" . | quote }} +{{- if .Values.controlPlane.supportGatewaySecretsInAllNamespaces }} +- name: KUMA_RUNTIME_KUBERNETES_SUPPORT_GATEWAY_SECRETS_IN_ALL_NAMESPACES + value: true +{{- end }} +{{- end }} + +{{- define "kuma.controlPlane.tls.general.caSecretName" -}} +{{ .Values.controlPlane.tls.general.caSecretName | default .Values.controlPlane.tls.general.secretName | default (printf "%s-tls-cert" (include "kuma.name" .)) | quote }} +{{- end }} + +{{- define "kuma.universal.defaultEnv" -}} +{{ if eq .Values.controlPlane.mode "zone" }} + {{ if .Values.ingress.enabled }} + {{ fail "Can't have ingress.enabled when running controlPlane.mode=='universal'" }} + {{ end }} + {{ if .Values.egress.enabled }} + {{ fail "Can't have egress.enabled when running controlPlane.mode=='universal'" }} + {{ end }} +{{ end }} + +env: +- name: KUMA_PLUGIN_POLICIES_ENABLED + value: {{ include "kuma.pluginPoliciesEnabled" . | quote }} +- name: KUMA_GENERAL_WORK_DIR + value: "/tmp/kuma" +- name: KUMA_ENVIRONMENT + value: "universal" +- name: KUMA_STORE_TYPE + value: "postgres" +- name: KUMA_STORE_POSTGRES_PORT + value: "{{ .Values.postgres.port }}" +- name: KUMA_DEFAULTS_SKIP_MESH_CREATION + value: {{ .Values.controlPlane.defaults.skipMeshCreation | quote }} +{{ if and (eq .Values.controlPlane.mode "zone") .Values.controlPlane.tls.general.secretName }} +- name: KUMA_GENERAL_TLS_CERT_FILE + value: /var/run/secrets/kuma.io/tls-cert/tls.crt +- name: KUMA_GENERAL_TLS_KEY_FILE + value: /var/run/secrets/kuma.io/tls-cert/tls.key +{{ end }} +- name: KUMA_MODE + value: {{ .Values.controlPlane.mode | quote }} +{{- if eq .Values.controlPlane.mode "zone" }} +- name: KUMA_MULTIZONE_ZONE_GLOBAL_ADDRESS + value: {{ .Values.controlPlane.kdsGlobalAddress }} +{{- end }} +{{- if .Values.controlPlane.zone }} +- name: KUMA_MULTIZONE_ZONE_NAME + value: {{ .Values.controlPlane.zone | quote }} +{{- end }} +{{- if and (eq .Values.controlPlane.mode "zone") (or .Values.controlPlane.tls.kdsZoneClient.secretName .Values.controlPlane.tls.kdsZoneClient.create) }} +- name: KUMA_MULTIZONE_ZONE_KDS_ROOT_CA_FILE + value: /var/run/secrets/kuma.io/kds-client-tls-cert/ca.crt +{{- end }} +{{- if not .Values.experimental.deltaKds }} +- name: KUMA_EXPERIMENTAL_KDS_DELTA_ENABLED + value: "false" +{{- end }} +{{- if .Values.controlPlane.tls.kdsZoneClient.skipVerify }} +- name: KUMA_MULTIZONE_ZONE_KDS_TLS_SKIP_VERIFY + value: "true" +{{- end }} +{{- if .Values.controlPlane.tls.apiServer.secretName }} +- name: KUMA_API_SERVER_HTTPS_TLS_CERT_FILE + value: /var/run/secrets/kuma.io/api-server-tls-cert/tls.crt +- name: KUMA_API_SERVER_HTTPS_TLS_KEY_FILE + value: /var/run/secrets/kuma.io/api-server-tls-cert/tls.key +{{- end }} +{{- if .Values.controlPlane.tls.apiServer.clientCertsSecretName }} +- name: KUMA_API_SERVER_AUTH_CLIENT_CERTS_DIR + value: /var/run/secrets/kuma.io/api-server-client-certs/ +{{- end }} +{{- if .Values.controlPlane.tls.kdsGlobalServer.secretName }} +- name: KUMA_MULTIZONE_GLOBAL_KDS_TLS_CERT_FILE + value: /var/run/secrets/kuma.io/kds-server-tls-cert/tls.crt +- name: KUMA_MULTIZONE_GLOBAL_KDS_TLS_KEY_FILE + value: /var/run/secrets/kuma.io/kds-server-tls-cert/tls.key +{{- end }} +- name: KUMA_STORE_POSTGRES_TLS_MODE + value: {{ .Values.postgres.tls.mode }} +{{- if or (eq .Values.postgres.tls.mode "verifyCa") (eq .Values.postgres.tls.mode "verifyFull") }} +{{- if empty .Values.postgres.tls.caSecretName }} +{{ fail "if mode is 'verifyCa' or 'verifyFull' then you must provide .Values.postgres.tls.caSecretName" }} +{{- end }} +{{- if .Values.postgres.tls.secretName }} +- name: KUMA_STORE_POSTGRES_TLS_CERT_PATH + value: /var/run/secrets/kuma.io/postgres-tls-cert/tls.crt +- name: KUMA_STORE_POSTGRES_TLS_KEY_PATH + value: /var/run/secrets/kuma.io/postgres-tls-cert/tls.key +{{- end }} +{{- if .Values.postgres.tls.caSecretName }} +- name: KUMA_STORE_POSTGRES_TLS_CA_PATH + value: /var/run/secrets/kuma.io/postgres-tls-cert/ca.crt +{{- end }} +{{- if .Values.postgres.tls.disableSSLSNI }} +- name: KUMA_STORE_POSTGRES_TLS_DISABLE_SSLSNI + value: {{ .Values.postgres.tls.disableSSLSNI }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cni-configmap.yaml b/charts/kuma/kuma/2.8.2/templates/cni-configmap.yaml new file mode 100644 index 000000000..8d27de9ef --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cni-configmap.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.cni.enabled (not .Values.experimental.ebpf.enabled) }} +kind: ConfigMap +apiVersion: v1 +metadata: + name: {{ include "kuma.name" . }}-cni-config + namespace: {{ .Values.cni.namespace }} + labels: {{ include "kuma.cniLabels" . | nindent 4 }} +data: + # The CNI network configuration to add to the plugin chain on each node. + cni_network_config: |- + { + "cniVersion": "0.3.1", + "name": "kuma-cni", + "type": "kuma-cni", + "log_level": "{{ .Values.cni.logLevel }}", + "kubernetes": { + "kubeconfig": "__KUBECONFIG_FILEPATH__", + "cni_bin_dir": "{{ .Values.cni.binDir }}", + "exclude_namespaces": [ "kube-system" ] + } + } + {{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cni-daemonset.yaml b/charts/kuma/kuma/2.8.2/templates/cni-daemonset.yaml new file mode 100644 index 000000000..b5d8db761 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cni-daemonset.yaml @@ -0,0 +1,152 @@ +{{- if .Values.cni.enabled }} +kind: DaemonSet +apiVersion: apps/v1 +metadata: + name: {{ include "kuma.name" . }}-cni-node + namespace: {{ .Values.cni.namespace }} + annotations: + ignore-check.kube-linter.io/run-as-non-root: "The container installs a CNI plugin" + labels: {{- include "kuma.cniLabels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "kuma.cniSelectorLabels" . | nindent 6 }} + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + template: + metadata: + labels: + {{- include "kuma.cniSelectorLabels" . | nindent 8 }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/cni-configmap.yaml") . | sha256sum }} + {{- range $key, $value := .Values.cni.podAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + spec: + # This, along with the CriticalAddonsOnly toleration below, + # marks the pod as a critical add-on, ensuring it gets + # priority scheduling and that its resources are reserved + # if it ever gets evicted. + priorityClassName: system-node-critical + {{- with .Values.cni.nodeSelector }} + nodeSelector: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.cni.tolerations }} + tolerations: + {{ toYaml . | nindent 8 }} + {{- end }} + tolerations: + # Make sure kuma-cni-node gets scheduled on all nodes. + - effect: NoSchedule + operator: Exists + # Mark the pod as a critical add-on for rescheduling. + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + serviceAccountName: {{ include "kuma.name" . }}-cni + # Minimize downtime during a rolling upgrade or deletion; tell Kubernetes to do a "force + # deletion": https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods. + terminationGracePeriodSeconds: 5 + securityContext: + {{- toYaml .Values.cni.podSecurityContext | trim | nindent 8 }} + containers: + - name: install-cni + imagePullPolicy: {{ .Values.cni.image.imagePullPolicy }} + {{- if not .Values.experimental.ebpf.enabled }} + image: {{ include "kuma.formatImage" (dict "image" .Values.cni.image "root" $) | quote }} + readinessProbe: + initialDelaySeconds: {{ .Values.cni.delayStartupSeconds }} + exec: + command: + - cat + - /tmp/ready + command: [ "sh", "-c", "--" ] + args: [ "sleep {{.Values.cni.delayStartupSeconds}} && exec /install-cni" ] + {{- else }} + {{- with .Values.cni.experimental.imageEbpf }} + image: {{ printf "%s/%s:%s" .registry .repository .tag | quote }} + {{- end }} + args: + - /app/mbctl + - --mode=kuma + - --use-reconnect=true + - --cni-mode=true + {{- if eq .Values.cni.logLevel "debug" }} + - --debug=true + {{- end }} + lifecycle: + preStop: + exec: + command: + - make + - --keep-going + - clean + {{- end }} + securityContext: + {{- toYaml .Values.cni.containerSecurityContext | trim | nindent 12 }} + {{- if .Values.experimental.ebpf.enabled }} + privileged: true + {{- end }} + {{- if not .Values.experimental.ebpf.enabled }} + env: + # Name of the CNI config file to create. + - name: CNI_CONF_NAME + value: "{{ .Values.cni.confName }}" + # The CNI network config to install on each node. + - name: CNI_NETWORK_CONFIG + valueFrom: + configMapKeyRef: + name: {{ include "kuma.name" . }}-cni-config + key: cni_network_config + - name: CNI_NET_DIR + value: "{{ .Values.cni.netDir }}" + # If true, deploy as a chained CNI plugin, otherwise deploy as a standalone CNI + - name: CHAINED_CNI_PLUGIN + value: "{{ .Values.cni.chained }}" + - name: CNI_LOG_LEVEL + value: "{{ .Values.cni.logLevel }}" + {{- end }} + resources: + {{- toYaml .Values.cni.resources | trim | nindent 12 }} + volumeMounts: + - mountPath: /host/opt/cni/bin + name: cni-bin-dir + - mountPath: /host/etc/cni/net.d + name: cni-net-dir + {{- if .Values.experimental.ebpf.enabled }} + - mountPath: /sys/fs/cgroup + name: sys-fs-cgroup + - mountPath: /host/proc + name: host-proc + - mountPath: /host/var/run + name: host-var-run + mountPropagation: Bidirectional + {{- end }} + - name: tmp + mountPath: /tmp + volumes: + # Used to install CNI. + - name: cni-bin-dir + hostPath: + path: {{ .Values.cni.binDir }} + - name: cni-net-dir + hostPath: + path: {{ .Values.cni.netDir }} + {{- if .Values.experimental.ebpf.enabled }} + - hostPath: + path: /var/run + name: host-var-run + - hostPath: + path: /sys/fs/cgroup + name: sys-fs-cgroup + - hostPath: + path: /proc + name: host-proc + {{- end }} + - name: tmp + emptyDir: {} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cni-rbac.yaml b/charts/kuma/kuma/2.8.2/templates/cni-rbac.yaml new file mode 100644 index 000000000..07af2b215 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cni-rbac.yaml @@ -0,0 +1,51 @@ +{{- if .Values.cni.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "kuma.name" . }}-cni + namespace: {{ .Values.cni.namespace }} + labels: {{ include "kuma.cniLabels" . | nindent 4 }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range . }} + - name: {{ . | quote }} + {{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "kuma.name" . }}-cni + labels: + {{ include "kuma.cniLabels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: + - nodes + verbs: + - get + - apiGroups: [""] + resources: + - pods + verbs: + - get + {{- if .Values.experimental.ebpf.enabled }} + - list + - watch + {{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kuma.name" . }}-cni + labels: + {{ include "kuma.cniLabels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kuma.name" . }}-cni +subjects: + - kind: ServiceAccount + name: {{ include "kuma.name" . }}-cni + namespace: {{ .Values.cni.namespace }} + {{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-configmap.yaml b/charts/kuma/kuma/2.8.2/templates/cp-configmap.yaml new file mode 100644 index 000000000..cb503033f --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-configmap.yaml @@ -0,0 +1,33 @@ +{{ $kumaCpLabels := include "kuma.cpLabels" . }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "kuma.name" . }}-control-plane-config + namespace: {{ .Release.Namespace }} + labels: {{ $kumaCpLabels | nindent 4 }} +data: + config.yaml: | + # use this file to override default configuration of `kuma-cp` + # + # see conf/kuma-cp.conf.yml for available settings + {{ if .Values.controlPlane.config }} + {{ .Values.controlPlane.config | nindent 4 }} + {{ end }} + +{{- $releaseNamespace := .Release.Namespace}} +{{- range $extraConfigMap := .Values.controlPlane.extraConfigMaps }} +{{- if $extraConfigMap.values }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $extraConfigMap.name }} + namespace: {{ $releaseNamespace }} + labels: {{ $kumaCpLabels | nindent 4 }} +data: + {{- range $fileName, $fileContents := $extraConfigMap.values }} + {{- $fileName | nindent 2 }}: | + {{- $fileContents | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-deployment.yaml b/charts/kuma/kuma/2.8.2/templates/cp-deployment.yaml new file mode 100644 index 000000000..61bb2d27f --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-deployment.yaml @@ -0,0 +1,398 @@ +{{ $kdsGlobalServerTLSSecretName := "" }} +{{ if eq .Values.controlPlane.mode "global" }} + {{ $kdsGlobalServerTLSSecretName = .Values.controlPlane.tls.kdsGlobalServer.secretName }} + {{ if and .Values.controlPlane.tls.kdsGlobalServer.create (not $kdsGlobalServerTLSSecretName) }} + {{ $kdsGlobalServerTLSSecretName = print (include "kuma.name" .) "-kds-global-server-tls" }} + {{ end }} +{{ end }} + +{{ $kdsZoneClientTLSSecretName := "" }} +{{ if eq .Values.controlPlane.mode "zone" }} + {{ $kdsZoneClientTLSSecretName = .Values.controlPlane.tls.kdsZoneClient.secretName }} + {{ if and .Values.controlPlane.tls.kdsZoneClient.create (not $kdsZoneClientTLSSecretName) }} + {{ $kdsZoneClientTLSSecretName = print (include "kuma.name" .) "-kds-zone-client-tls" }} + {{ end }} +{{ end }} + +{{ if not (or (eq .Values.controlPlane.mode "zone") (eq .Values.controlPlane.mode "global") (eq .Values.controlPlane.mode "standalone")) }} + {{ $msg := printf "controlPlane.mode invalid got:'%s' supported values: global,zone,standalone" .Values.controlPlane.mode }} + {{ fail $msg }} +{{ end }} +{{ if eq .Values.controlPlane.mode "zone" }} + {{ if not (empty .Values.controlPlane.zone) }} + {{ if gt (len .Values.controlPlane.zone) 253 }} + {{ fail "controlPlane.zone must be no more than 253 characters" }} + {{ else }} + {{ if not (regexMatch "^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" .Values.controlPlane.zone) }} + {{ fail "controlPlane.zone must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character" }} + {{ end }} + {{ end }} + {{ end }} + {{ if not (empty .Values.controlPlane.kdsGlobalAddress) }} + {{ $url := urlParse .Values.controlPlane.kdsGlobalAddress }} + {{ if not (or (eq $url.scheme "grpcs") (eq $url.scheme "grpc")) }} + {{ $msg := printf "controlPlane.kdsGlobalAddress must be a url with scheme grpcs:// or grpc:// got:'%s'" .Values.controlPlane.kdsGlobalAddress }} + {{ fail $msg }} + {{ end }} + {{ end }} +{{ else }} + {{ if not (empty .Values.controlPlane.zone) }} + {{ fail "Can't specify a controlPlane.zone when controlPlane.mode!='zone'" }} + {{ end }} + {{ if not (empty .Values.controlPlane.kdsGlobalAddress) }} + {{ fail "Can't specify a controlPlane.kdsGlobalAddress when controlPlane.mode!='zone'" }} + {{ end }} +{{ end }} + +{{- $defaultEnv := include "kuma.defaultEnv" . | fromYaml | pluck "env" | first }} +{{- if eq .Values.controlPlane.environment "universal" }} +{{- $defaultEnv = include "kuma.universal.defaultEnv" . | fromYaml | pluck "env" | first }} +{{- end }} +{{- $defaultEnvDict := dict }} +{{- range $index, $item := $defaultEnv }} +{{- $name := $item.name | upper }} +{{- $defaultEnvDict := set $defaultEnvDict $name $item.value }} +{{- end }} +{{- $envVarsCopy := deepCopy .Values.controlPlane.envVars }} +{{- $mergedEnv := merge $envVarsCopy $defaultEnvDict }} +{{- $defaultSecrets := include "kuma.parentSecrets" . | fromYaml }} +{{- $extraSecrets := .Values.controlPlane.extraSecrets }} +{{- $mergedSecrets := merge $extraSecrets $defaultSecrets }} + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "kuma.name" . }}-control-plane + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} + annotations: {{ include "kuma.cpDeploymentAnnotations" . | nindent 4 }} +spec: + {{- if not .Values.controlPlane.autoscaling.enabled }} + replicas: {{ .Values.controlPlane.replicas }} + {{- end }} + minReadySeconds: {{ .Values.controlPlane.minReadySeconds }} + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + selector: + matchLabels: + {{- include "kuma.selectorLabels" . | nindent 6 }} + app: {{ include "kuma.name" . }}-control-plane + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/cp-configmap.yaml") . | sha256sum }} + {{- if .Values.restartOnSecretChange }} + checksum/tls-secrets: {{ include (print $.Template.BasePath "/cp-webhooks-and-secrets.yaml") . | sha256sum }} + {{- end }} + {{- range $key, $value := $.Values.controlPlane.podAnnotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + labels: {{ include "kuma.cpLabels" . | nindent 8 }} + spec: + {{- with .Values.controlPlane.affinity }} + affinity: {{ tpl (toYaml . | nindent 8) $ }} + {{- end }} + {{- with .Values.controlPlane.topologySpreadConstraints }} + topologySpreadConstraints: {{ tpl (toYaml . | nindent 8) $ }} + {{- end }} + securityContext: + {{- toYaml .Values.controlPlane.podSecurityContext | trim | nindent 8 }} + serviceAccountName: {{ include "kuma.name" . }}-control-plane + automountServiceAccountToken: {{ .Values.controlPlane.automountServiceAccountToken }} + {{- with .Values.controlPlane.nodeSelector }} + nodeSelector: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.controlPlane.tolerations }} + tolerations: + {{ toYaml . | nindent 8 }} + {{- end }} + hostNetwork: {{ .Values.controlPlane.hostNetwork }} + terminationGracePeriodSeconds: {{ .Values.controlPlane.terminationGracePeriodSeconds }} + {{- if (eq .Values.controlPlane.environment "universal") }} + initContainers: + - name: migration + image: {{ include "kuma.formatImage" (dict "image" .Values.controlPlane.image "root" $) | quote }} + imagePullPolicy: {{ .Values.controlPlane.image.pullPolicy }} + securityContext: + {{- toYaml .Values.controlPlane.containerSecurityContext | trim | nindent 12 }} + env: + {{- range $key, $value := $mergedEnv }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- range $element := .Values.controlPlane.secrets }} + - name: {{ $element.Env }} + valueFrom: + secretKeyRef: + name: {{ $element.Secret }} + key: {{ $element.Key }} + {{- end }} + args: + - migrate + - up + - --log-level=info + - --config-file=/etc/kuma.io/kuma-control-plane/config.yaml + resources: + {{- if .Values.controlPlane.resources }} + {{- .Values.controlPlane.resources | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.postgres.tls.caSecretName }} + - name: postgres-tls-cert-ca + subPath: ca.crt + mountPath: /var/run/secrets/kuma.io/postgres-tls-cert/ca.crt + readOnly: true + {{- end }} + {{- if .Values.postgres.tls.secretName }} + - name: postgres-tls-cert + subPath: tls.crt + mountPath: /var/run/secrets/kuma.io/postgres-tls-cert/tls.crt + readOnly: true + - name: postgres-tls-cert + subPath: tls.key + mountPath: /var/run/secrets/kuma.io/postgres-tls-cert/tls.key + readOnly: true + {{- end }} + - name: {{ include "kuma.name" . }}-control-plane-config + mountPath: /etc/kuma.io/kuma-control-plane + readOnly: true + {{- end }} + containers: + - name: control-plane + image: {{ include "kuma.formatImage" (dict "image" .Values.controlPlane.image "root" $) | quote }} + imagePullPolicy: {{ .Values.controlPlane.image.pullPolicy }} + securityContext: + {{- toYaml .Values.controlPlane.containerSecurityContext | trim | nindent 12 }} + env: + {{- range $key, $value := $mergedEnv }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- range $element := .Values.controlPlane.secrets }} + - name: {{ $element.Env }} + valueFrom: + secretKeyRef: + name: {{ $element.Secret }} + key: {{ $element.Key }} + {{- end }} + - name: KUMA_INTER_CP_CATALOG_INSTANCE_ADDRESS + valueFrom: + fieldRef: + fieldPath: status.podIP + args: + - run + - --log-level={{ .Values.controlPlane.logLevel }} + - --log-output-path={{ .Values.controlPlane.logOutputPath }} + - --config-file=/etc/kuma.io/kuma-control-plane/config.yaml + ports: + - containerPort: 5680 + name: diagnostics + protocol: TCP + - containerPort: 5681 + - containerPort: 5682 + - containerPort: {{ .Values.controlPlane.admissionServerPort | default "5443" }} + {{- if ne .Values.controlPlane.mode "global" }} + - containerPort: 5678 + {{- end }} + livenessProbe: + timeoutSeconds: 10 + httpGet: + path: /healthy + port: 5680 + readinessProbe: + timeoutSeconds: 10 + httpGet: + path: /ready + port: 5680 + resources: + {{- if .Values.controlPlane.resources }} + {{- .Values.controlPlane.resources | toYaml | nindent 12 }} + {{- end }} + {{ with .Values.controlPlane.lifecycle }} + lifecycle: {{ . | toYaml | nindent 14 }} + {{ end }} + volumeMounts: + {{- if eq .Values.controlPlane.environment "kubernetes" }} + {{- if not .Values.controlPlane.automountServiceAccountToken }} + - mountPath: /var/run/secrets/kubernetes.io/serviceaccount + name: serviceaccount-token + readOnly: true + {{- end }} + - name: general-tls-cert + mountPath: /var/run/secrets/kuma.io/tls-cert/tls.crt + subPath: tls.crt + readOnly: true + - name: general-tls-cert + mountPath: /var/run/secrets/kuma.io/tls-cert/tls.key + subPath: tls.key + readOnly: true + - name: general-tls-cert{{- if .Values.controlPlane.tls.general.caSecretName }}-ca{{- end }} + mountPath: /var/run/secrets/kuma.io/tls-cert/ca.crt + subPath: ca.crt + readOnly: true + {{- end }} + {{- if and (eq .Values.controlPlane.environment "universal") (eq .Values.controlPlane.mode "zone") }} + {{- if .Values.controlPlane.tls.general.secretName }} + - name: general-tls-cert + mountPath: /var/run/secrets/kuma.io/tls-cert/tls.crt + subPath: tls.crt + readOnly: true + - name: general-tls-cert + mountPath: /var/run/secrets/kuma.io/tls-cert/tls.key + subPath: tls.key + readOnly: true + - name: general-tls-cert{{- if .Values.controlPlane.tls.general.caSecretName }}-ca{{- end }} + mountPath: /var/run/secrets/kuma.io/tls-cert/ca.crt + subPath: ca.crt + readOnly: true + {{- end }} + {{- end }} + - name: {{ include "kuma.name" . }}-control-plane-config + mountPath: /etc/kuma.io/kuma-control-plane + readOnly: true + {{- if .Values.controlPlane.tls.apiServer.secretName }} + - name: api-server-tls-cert + mountPath: /var/run/secrets/kuma.io/api-server-tls-cert + readOnly: true + {{- end }} + {{- if .Values.postgres.tls.caSecretName }} + - name: postgres-tls-cert-ca + subPath: ca.crt + mountPath: /var/run/secrets/kuma.io/postgres-tls-cert/ca.crt + readOnly: true + {{- end }} + {{- if .Values.postgres.tls.secretName }} + - name: postgres-tls-cert + subPath: tls.crt + mountPath: /var/run/secrets/kuma.io/postgres-tls-cert/tls.crt + readOnly: true + - name: postgres-tls-cert + subPath: tls.key + mountPath: /var/run/secrets/kuma.io/postgres-tls-cert/tls.key + readOnly: true + {{- end }} + {{- if .Values.controlPlane.tls.apiServer.clientCertsSecretName }} + - name: api-server-client-certs + mountPath: /var/run/secrets/kuma.io/api-server-client-certs + readOnly: true + {{- end }} + {{- if $kdsGlobalServerTLSSecretName }} + - name: kds-server-tls-cert + mountPath: /var/run/secrets/kuma.io/kds-server-tls-cert + readOnly: true + {{- end }} + {{- if $kdsZoneClientTLSSecretName }} + - name: kds-client-tls-cert + mountPath: /var/run/secrets/kuma.io/kds-client-tls-cert + readOnly: true + {{- end }} + {{- range $extraConfigMap := .Values.controlPlane.extraConfigMaps }} + - name: {{ $extraConfigMap.name }} + mountPath: {{ $extraConfigMap.mountPath }} + readOnly: {{ $extraConfigMap.readOnly }} + {{- end }} + {{- range $mergedSecret := $mergedSecrets }} + - name: {{ $mergedSecret.name }} + mountPath: {{ $mergedSecret.mountPath }} + subPath: {{ $mergedSecret.subPath }} + readOnly: {{ $mergedSecret.readOnly }} + {{- end }} + - name: tmp + mountPath: /tmp + volumes: + {{- if eq .Values.controlPlane.environment "kubernetes" }} + {{- if not .Values.controlPlane.automountServiceAccountToken }} + - name: serviceaccount-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + expirationSeconds: 3600 + path: token + - configMap: + name: kube-root-ca.crt + items: + - key: ca.crt + path: ca.crt + - downwardAPI: + items: + - fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + path: namespace + {{- end }} + {{- if .Values.controlPlane.tls.general.secretName }} + - name: general-tls-cert + secret: + secretName: {{ .Values.controlPlane.tls.general.secretName }} + {{- else }} + - name: general-tls-cert + secret: + secretName: {{ include "kuma.name" . }}-tls-cert + {{- end }} + {{- if .Values.controlPlane.tls.general.caSecretName }} + - name: general-tls-cert-ca + secret: + secretName: {{ .Values.controlPlane.tls.general.caSecretName }} + {{- end }} + {{- end }} + {{- if and (eq .Values.controlPlane.environment "universal") (eq .Values.controlPlane.mode "zone") }} + {{- if .Values.controlPlane.tls.general.secretName }} + - name: general-tls-cert + secret: + secretName: {{ .Values.controlPlane.tls.general.secretName }} + {{- end }} + {{- if .Values.controlPlane.tls.general.caSecretName }} + - name: general-tls-cert-ca + secret: + secretName: {{ .Values.controlPlane.tls.general.caSecretName }} + {{- end }} + {{- end }} + {{- if .Values.controlPlane.tls.apiServer.secretName }} + - name: api-server-tls-cert + secret: + secretName: {{ .Values.controlPlane.tls.apiServer.secretName }} + {{- end }} + {{- if .Values.postgres.tls.caSecretName }} + - name: postgres-tls-cert-ca + secret: + secretName: {{ .Values.postgres.tls.caSecretName }} + {{- end }} + {{- if .Values.postgres.tls.secretName }} + - name: postgres-tls-cert + secret: + secretName: {{ .Values.postgres.tls.secretName }} + {{- end }} + {{- if .Values.controlPlane.tls.apiServer.clientCertsSecretName }} + - name: api-server-client-certs + secret: + secretName: {{ .Values.controlPlane.tls.apiServer.clientCertsSecretName }} + {{- end }} + {{- if $kdsGlobalServerTLSSecretName }} + - name: kds-server-tls-cert + secret: + secretName: {{ $kdsGlobalServerTLSSecretName }} + {{- end }} + {{- if $kdsZoneClientTLSSecretName }} + - name: kds-client-tls-cert + secret: + secretName: {{ $kdsZoneClientTLSSecretName }} + {{- end }} + - name: {{ include "kuma.name" . }}-control-plane-config + configMap: + name: {{ include "kuma.name" . }}-control-plane-config + {{- range $extraConfigMap := .Values.controlPlane.extraConfigMaps }} + - name: {{ $extraConfigMap.name }} + configMap: + name: {{ $extraConfigMap.name }} + {{- end }} + {{- range $mergedSecret := $mergedSecrets }} + - name: {{ $mergedSecret.name }} + secret: + secretName: {{ $mergedSecret.name }} + {{- end }} + - name: tmp + emptyDir: {} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-global-sync-service.yaml b/charts/kuma/kuma/2.8.2/templates/cp-global-sync-service.yaml new file mode 100644 index 000000000..c5b3555a8 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-global-sync-service.yaml @@ -0,0 +1,33 @@ +{{- if and (eq .Values.controlPlane.mode "global") .Values.controlPlane.globalZoneSyncService.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "kuma.controlPlane.globalZoneSync.serviceName" . }} + namespace: {{ .Release.Namespace }} + annotations: + {{- range $key, $value := .Values.controlPlane.globalZoneSyncService.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +spec: + type: {{ .Values.controlPlane.globalZoneSyncService.type }} + {{- if .Values.controlPlane.globalZoneSyncService.loadBalancerIP }} + loadBalancerIP: {{ .Values.controlPlane.globalZoneSyncService.loadBalancerIP }} + {{- end }} + {{- if .Values.controlPlane.globalZoneSyncService.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range .Values.controlPlane.globalZoneSyncService.loadBalancerSourceRanges }} + - {{.}} + {{- end }} + {{- end }} + ports: + - port: {{ .Values.controlPlane.globalZoneSyncService.port }} + appProtocol: {{ .Values.controlPlane.globalZoneSyncService.protocol }} + {{- if and (eq .Values.controlPlane.globalZoneSyncService.type "NodePort") .Values.controlPlane.globalZoneSyncService.nodePort }} + nodePort: {{ .Values.controlPlane.globalZoneSyncService.nodePort }} + {{- end }} + name: global-zone-sync + selector: + app: {{ include "kuma.name" . }}-control-plane + {{ include "kuma.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-hpa.yaml b/charts/kuma/kuma/2.8.2/templates/cp-hpa.yaml new file mode 100644 index 000000000..dc4981020 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-hpa.yaml @@ -0,0 +1,24 @@ +{{- if .Values.controlPlane.autoscaling.enabled }} +{{ if .Capabilities.APIVersions.Has "autoscaling/v2" }} +apiVersion: "autoscaling/v2" +{{ else }} +apiVersion: "autoscaling/v1" +{{ end }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "kuma.name" . }}-control-plane + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "kuma.name" . }}-control-plane + minReplicas: {{ .Values.controlPlane.autoscaling.minReplicas }} + maxReplicas: {{ .Values.controlPlane.autoscaling.maxReplicas }} + {{ if .Capabilities.APIVersions.Has "autoscaling/v2" }} + metrics: {{- toYaml .Values.controlPlane.autoscaling.metrics | nindent 4 }} + {{ else }} + targetCPUUtilizationPercentage: {{ .Values.controlPlane.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-ingress.yaml b/charts/kuma/kuma/2.8.2/templates/cp-ingress.yaml new file mode 100644 index 000000000..8ceae01f8 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-ingress.yaml @@ -0,0 +1,25 @@ +{{- if .Values.controlPlane.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "kuma.controlPlane.serviceName" . }} + namespace: {{ .Release.Namespace }} + {{- with .Values.controlPlane.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +spec: + ingressClassName: {{ .Values.controlPlane.ingress.ingressClassName }} + rules: + - host: {{ .Values.controlPlane.ingress.hostname }} + http: + paths: + - path: {{ .Values.controlPlane.ingress.path }} + pathType: {{ .Values.controlPlane.ingress.pathType }} + backend: + service: + name: {{ include "kuma.controlPlane.serviceName" . }} + port: + number: {{ .Values.controlPlane.ingress.servicePort }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-kds-global-server-secret.yaml b/charts/kuma/kuma/2.8.2/templates/cp-kds-global-server-secret.yaml new file mode 100644 index 000000000..5ea3314a3 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-kds-global-server-secret.yaml @@ -0,0 +1,15 @@ +{{ if and (eq .Values.controlPlane.mode "global") .Values.controlPlane.tls.kdsGlobalServer.create }} +apiVersion: v1 +kind: Secret +metadata: +{{ with .Values.controlPlane.tls.kdsGlobalServer.secretName }} + name: {{ . }} +{{ else }} + name: {{ include "kuma.name" . }}-kds-global-server-tls +{{ end }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +type: kubernetes.io/tls +stringData: + tls.crt: {{ required "you must provide a kds tls cert" .Values.controlPlane.tls.kdsGlobalServer.cert | quote }} + tls.key: {{ required "you must provide a kds tls key" .Values.controlPlane.tls.kdsGlobalServer.key | quote }} +{{ end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-kds-zone-client-tls-secret.yaml b/charts/kuma/kuma/2.8.2/templates/cp-kds-zone-client-tls-secret.yaml new file mode 100644 index 000000000..99b15c5bd --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-kds-zone-client-tls-secret.yaml @@ -0,0 +1,13 @@ +{{ if and (eq .Values.controlPlane.mode "zone") .Values.controlPlane.tls.kdsZoneClient.create }} +apiVersion: v1 +kind: Secret +metadata: +{{ with .Values.controlPlane.tls.kdsZoneClient.secretName }} + name: {{ . }} +{{ else }} + name: {{ include "kuma.name" . }}-kds-zone-client-tls +{{ end }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +stringData: + ca.crt: {{ required "you must provide a kds cert" .Values.controlPlane.tls.kdsZoneClient.cert | quote }} +{{ end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-pdb.yaml b/charts/kuma/kuma/2.8.2/templates/cp-pdb.yaml new file mode 100644 index 000000000..bb29bfd20 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-pdb.yaml @@ -0,0 +1,20 @@ +{{ if $.Values.controlPlane.podDisruptionBudget.enabled }} +{{ if .Capabilities.APIVersions.Has "policy/v1" }} +apiVersion: policy/v1 +{{ else if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +{{ fail "pod disruption budgets are not supported by this version of kubernetes" }} +{{ end }} +kind: PodDisruptionBudget +metadata: + name: {{ include "kuma.name" . }}-control-plane + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +spec: + maxUnavailable: {{ .Values.controlPlane.podDisruptionBudget.maxUnavailable }} + selector: + matchLabels: + {{- include "kuma.selectorLabels" . | nindent 6 }} + app: {{ include "kuma.name" . }}-control-plane +{{ end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-rbac.yaml b/charts/kuma/kuma/2.8.2/templates/cp-rbac.yaml new file mode 100644 index 000000000..2c0145f0c --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-rbac.yaml @@ -0,0 +1,315 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "kuma.name" . }}-control-plane + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +{{- with .Values.controlPlane.serviceAccountAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range . }} + - name: {{ . | quote }} + {{- end }} +{{- end }} +{{- if (eq .Values.controlPlane.environment "kubernetes") }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "kuma.name" . }}-control-plane + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - namespaces + - pods + - configmaps + - nodes +{{- if .Values.controlPlane.supportGatewaySecretsInAllNamespaces }} + - secrets +{{- end }} + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - secrets + verbs: + - list + - watch + - apiGroups: + - "discovery.k8s.io" + resources: + - endpointslices + verbs: + - get + - list + - watch + - apiGroups: + - "apps" + resources: + - deployments + - replicasets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - "batch" + resources: + - jobs + verbs: + - get + - list + - watch + - apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses + - gateways + - referencegrants + - httproutes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses/status + - gateways/status + - httproutes/status + verbs: + - get + - patch + - update + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - apiGroups: + - "" + resources: + - services + verbs: + - get + - delete + - list + - watch + - create + - update + - patch + - apiGroups: + - "discovery.k8s.io" + resources: + - endpointslices + verbs: + - get + - list + - watch + - apiGroups: + - kuma.io + resources: + - dataplanes + - dataplaneinsights + - meshes + - zones + - zoneinsights + - zoneingresses + - zoneingressinsights + - zoneegresses + - zoneegressinsights + - meshinsights + - serviceinsights + - proxytemplates + - ratelimits + - trafficpermissions + - trafficroutes + - timeouts + - retries + - circuitbreakers + - virtualoutbounds + - containerpatches + - externalservices + - faultinjections + - healthchecks + - trafficlogs + - traffictraces + - meshgateways + - meshgatewayroutes + - meshgatewayinstances + - meshgatewayconfigs + {{- range $policy, $v := .Values.plugins.policies }} + {{- if $v }} + - {{ $policy }} + {{- end}} + {{- end}} + {{- range $policy, $v := .Values.plugins.resources }} + {{- if $v }} + - {{ $policy }} + {{- end}} + {{- end}} + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - kuma.io + resources: + - meshgatewayinstances/status + - meshgatewayinstances/finalizers + - meshes/finalizers + - dataplanes/finalizers + verbs: + - get + - patch + - update + - apiGroups: + - "" + resources: + - pods/finalizers + verbs: + - get + - patch + - update + {{- if .Values.cni.enabled }} + - apiGroups: + - k8s.cni.cncf.io + resources: + - network-attachment-definitions + verbs: + - get + - list + - watch + - create + - delete + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + verbs: + - update + - apiGroups: + - "pods" + resources: + - pods + verbs: + - list + {{- end }} + # validate k8s token before issuing mTLS cert + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kuma.name" . }}-control-plane + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kuma.name" . }}-control-plane +subjects: + - kind: ServiceAccount + name: {{ include "kuma.name" . }}-control-plane + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "kuma.name" . }}-control-plane + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + # leader-for-life election deletes Pods in some circumstances + - apiGroups: + - "" + resources: + - pods + verbs: + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "kuma.name" . }}-control-plane + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "kuma.name" . }}-control-plane +subjects: + - kind: ServiceAccount + name: {{ include "kuma.name" . }}-control-plane + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-service.yaml b/charts/kuma/kuma/2.8.2/templates/cp-service.yaml new file mode 100644 index 000000000..3b9c3e31f --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-service.yaml @@ -0,0 +1,49 @@ +{{ if .Values.controlPlane.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "kuma.controlPlane.serviceName" . }} + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} + annotations: + {{- range $key, $value := .Values.controlPlane.service.annotations }} + {{- if $value }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.controlPlane.service.type }} + ports: + - port: 5680 + name: diagnostics + appProtocol: http + - port: 5681 + name: http-api-server + appProtocol: http + {{- if and (eq .Values.controlPlane.service.type "NodePort") .Values.controlPlane.service.apiServer.http.nodePort }} + nodePort: {{ .Values.controlPlane.service.apiServer.http.nodePort }} + {{- end }} + - port: 5682 + name: https-api-server + appProtocol: https + {{- if and (eq .Values.controlPlane.service.type "NodePort") .Values.controlPlane.service.apiServer.https.nodePort }} + nodePort: {{ .Values.controlPlane.service.apiServer.https.nodePort }} + {{- end }} + {{- if ne .Values.controlPlane.environment "universal" }} + - port: 443 + name: https-admission-server + targetPort: {{ .Values.controlPlane.admissionServerPort | default "5443" }} + appProtocol: https + {{- end }} + {{- if ne .Values.controlPlane.mode "global" }} + - port: 5676 + name: mads-server + appProtocol: https + - port: 5678 + name: dp-server + appProtocol: https + {{- end }} + selector: + app: {{ include "kuma.name" . }}-control-plane + {{- include "kuma.selectorLabels" . | nindent 4 }} +{{ end }} diff --git a/charts/kuma/kuma/2.8.2/templates/cp-webhooks-and-secrets.yaml b/charts/kuma/kuma/2.8.2/templates/cp-webhooks-and-secrets.yaml new file mode 100644 index 000000000..8d9ba3169 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/cp-webhooks-and-secrets.yaml @@ -0,0 +1,337 @@ +{{- if not (eq (empty .Values.controlPlane.tls.general.caBundle) (empty .Values.controlPlane.tls.general.secretName)) }} + {{ fail "You need to send both or neither of controlPlane.tls.general.caBundle and controlPlane.tls.general.secretName"}} +{{- end }} +{{- $caBundle := .Values.controlPlane.tls.general.caBundle }} +{{/* +Generate certificates +see: https://masterminds.github.io/sprig/crypto.html +see: https://medium.com/nuvo-group-tech/move-your-certs-to-helm-4f5f61338aca +see: https://github.com/networkservicemesh/networkservicemesh/blob/804ad5026bb5dbd285c220f15395fe25e46f5edb/deployments/helm/nsm/charts/admission-webhook/templates/admission-webhook-secret.tpl + +We only autogenerate certs if user did not chose their own secret. +We only autogenerate certs if the cert is not yet generated. This way we keep the secrets between HELM upgrades. +*/}} + +{{- if eq .Values.controlPlane.tls.general.secretName "" -}} +{{- $cert := "" }} +{{- $key := "" }} +{{- $secretName := print (include "kuma.name" .) "-tls-cert" }} + +{{- $secret := (lookup "v1" "Secret" .Release.Namespace $secretName) -}} +{{- if $secret -}} + {{- $cert = index $secret.data "tls.crt" -}} + {{- $key = index $secret.data "tls.key" -}} + {{- $caBundle = index $secret.data "ca.crt" -}} +{{- else -}} + {{- $commonName := (include "kuma.controlPlane.serviceName" .) -}} + {{- $altNames := list (printf "%s.%s" $commonName .Release.Namespace) (printf "%s.%s.svc" $commonName .Release.Namespace) -}} + {{- $certTTL := 3650 -}} + {{- $ca := genCA "kuma-ca" $certTTL -}} + + {{- $genCert := genSignedCert $commonName nil $altNames $certTTL $ca -}} + {{- $cert = $genCert.Cert | b64enc -}} + {{- $key = $genCert.Key | b64enc -}} + {{ $caBundle = $ca.Cert | b64enc }} +{{- end -}} +--- +apiVersion: v1 +kind: Secret +type: kubernetes.io/tls +metadata: + name: {{ $secretName }} + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +data: + tls.crt: {{ $cert }} + tls.key: {{ $key }} + ca.crt: {{ $caBundle }} +{{- end }} +{{- if (eq .Values.controlPlane.environment "kubernetes") }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ include "kuma.name" . }}-admission-mutating-webhook-configuration + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +webhooks: + - name: mesh.defaulter.kuma-admission.kuma.io + admissionReviewVersions: ["v1"] + failurePolicy: Fail + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system"] + clientConfig: + caBundle: {{ $caBundle }} + service: + namespace: {{ .Release.Namespace }} + name: {{ include "kuma.controlPlane.serviceName" . }} + path: /default-kuma-io-v1alpha1-mesh + rules: + - apiGroups: + - kuma.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - meshes + - meshgateways + {{- range $policy, $v := .Values.plugins.policies }} + {{- if $v }} + - {{ $policy }} + {{- end}} + {{- end}} + {{- range $policy, $v := .Values.plugins.resources }} + {{- if $v }} + - {{ $policy }} + {{- end}} + {{- end}} + sideEffects: None + - name: owner-reference.kuma-admission.kuma.io + admissionReviewVersions: ["v1"] + failurePolicy: Fail + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system"] + clientConfig: + caBundle: {{ $caBundle }} + service: + namespace: {{ .Release.Namespace }} + name: {{ include "kuma.controlPlane.serviceName" . }} + path: /owner-reference-kuma-io-v1alpha1 + rules: + - apiGroups: + - kuma.io + apiVersions: + - v1alpha1 + operations: + - CREATE + resources: + - circuitbreakers + - externalservices + - faultinjections + - healthchecks + - meshgateways + - meshgatewayroutes + - proxytemplates + - ratelimits + - retries + - timeouts + - trafficlogs + - trafficpermissions + - trafficroutes + - traffictraces + - virtualoutbounds + {{- range $policy, $v := .Values.plugins.policies }} + {{- if $v }} + - {{ $policy }} + {{- end}} + {{- end}} + {{- range $policy, $v := .Values.plugins.resources }} + {{- if $v }} + - {{ $policy }} + {{- end}} + {{- end}} + {{ .Values.controlPlane.webhooks.ownerReference.additionalRules | nindent 6 }} + sideEffects: None + {{- if ne .Values.controlPlane.mode "global" }} + - name: namespace-kuma-injector.kuma.io + admissionReviewVersions: ["v1"] + failurePolicy: {{ .Values.controlPlane.injectorFailurePolicy }} + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system"] + - key: kuma.io/sidecar-injection + operator: In + values: ["enabled", "true"] + clientConfig: + caBundle: {{ $caBundle }} + service: + namespace: {{ .Release.Namespace }} + name: {{ include "kuma.controlPlane.serviceName" . }} + path: /inject-sidecar + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + resources: + - pods + sideEffects: None + - name: pods-kuma-injector.kuma.io + admissionReviewVersions: ["v1"] + failurePolicy: {{ .Values.controlPlane.injectorFailurePolicy }} + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system"] + objectSelector: + matchLabels: + kuma.io/sidecar-injection: enabled + clientConfig: + caBundle: {{ $caBundle }} + service: + namespace: {{ .Release.Namespace }} + name: {{ include "kuma.controlPlane.serviceName" . }} + path: /inject-sidecar + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + resources: + - pods + sideEffects: None + {{- end }} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: {{ include "kuma.name" . }}-validating-webhook-configuration + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.cpLabels" . | nindent 4 }} +webhooks: + - name: validator.kuma-admission.kuma.io + admissionReviewVersions: ["v1"] + failurePolicy: Fail + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system"] + clientConfig: + caBundle: {{ $caBundle }} + service: + namespace: {{ .Release.Namespace }} + name: {{ include "kuma.controlPlane.serviceName" . }} + path: /validate-kuma-io-v1alpha1 + rules: + - apiGroups: + - kuma.io + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - circuitbreakers + - dataplanes + - externalservices + - faultinjections + - meshgatewayinstances + - healthchecks + - meshes + - meshgateways + - meshgatewayroutes + - proxytemplates + - ratelimits + - retries + - trafficlogs + - trafficpermissions + - trafficroutes + - traffictraces + - virtualoutbounds + - zones + - containerpatches + {{- range $policy, $v := .Values.plugins.policies }} + {{- if $v }} + - {{ $policy }} + {{- end}} + {{- end}} + {{- range $policy, $v := .Values.plugins.resources }} + {{- if $v }} + - {{ $policy }} + {{- end}} + {{- end}} + {{ .Values.controlPlane.webhooks.validator.additionalRules | nindent 6 }} + sideEffects: None + {{- if ne .Values.controlPlane.mode "global" }} + - name: service.validator.kuma-admission.kuma.io + admissionReviewVersions: ["v1"] + failurePolicy: Ignore + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system"] + clientConfig: + caBundle: {{ $caBundle }} + service: + namespace: {{ .Release.Namespace }} + name: {{ include "kuma.controlPlane.serviceName" . }} + path: /validate-v1-service + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - services + sideEffects: None + {{- end }} + - name: secret.validator.kuma-admission.kuma.io + admissionReviewVersions: ["v1"] + namespaceSelector: + matchLabels: + kuma.io/system-namespace: "true" + failurePolicy: Ignore + clientConfig: + caBundle: {{ $caBundle }} + service: + namespace: {{ .Release.Namespace }} + name: {{ include "kuma.controlPlane.serviceName" . }} + path: /validate-v1-secret + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - secrets + sideEffects: None + - name: gateway.validator.kuma-admission.kuma.io + admissionReviewVersions: ["v1"] + failurePolicy: Ignore + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system"] + clientConfig: + caBundle: {{ $caBundle }} + service: + namespace: {{ .Release.Namespace }} + name: {{ include "kuma.controlPlane.serviceName" . }} + path: /validate-gatewayclass + rules: + - apiGroups: + - "gateway.networking.k8s.io" + apiVersions: + - v1beta1 + operations: + - CREATE + resources: + - gatewayclasses + sideEffects: None +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/egress-deployment.yaml b/charts/kuma/kuma/2.8.2/templates/egress-deployment.yaml new file mode 100644 index 000000000..7655a3fa7 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/egress-deployment.yaml @@ -0,0 +1,137 @@ +{{- if .Values.egress.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "kuma.name" . }}-egress + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.egressLabels" . | nindent 4 }} +spec: + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + {{- if not .Values.egress.autoscaling.enabled }} + replicas: {{ .Values.egress.replicas }} + {{- end }} + selector: + matchLabels: + {{- include "kuma.selectorLabels" . | nindent 6 }} + app: {{ include "kuma.name" . }}-egress + template: + metadata: + annotations: + kuma.io/egress: enabled + {{- range $key, $value := merge .Values.egress.podAnnotations .Values.egress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + labels: + {{- include "kuma.egressLabels" . | nindent 8 }} + spec: + {{- with .Values.egress.affinity }} + affinity: {{ tpl (toYaml . | nindent 8) $ }} + {{- end }} + {{- with .Values.egress.topologySpreadConstraints }} + topologySpreadConstraints: {{ tpl (toYaml . | nindent 8) $ }} + {{- end }} + securityContext: + {{- toYaml .Values.egress.podSecurityContext | trim | nindent 8 }} + serviceAccountName: {{ include "kuma.name" . }}-egress + automountServiceAccountToken: {{ .Values.egress.automountServiceAccountToken }} + {{- with .Values.egress.nodeSelector }} + nodeSelector: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.egress.tolerations }} + tolerations: + {{ toYaml . | nindent 8 }} + {{- end }} + containers: + - name: egress + image: {{ include "kuma.formatImage" (dict "image" .Values.dataPlane.image "root" $) | quote }} + imagePullPolicy: {{ .Values.dataPlane.image.pullPolicy }} + securityContext: + {{- toYaml .Values.egress.containerSecurityContext | trim | nindent 12 }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: KUMA_CONTROL_PLANE_URL + value: "https://{{ include "kuma.controlPlane.serviceName" . }}.{{ .Release.Namespace }}:5678" + - name: KUMA_CONTROL_PLANE_CA_CERT_FILE + value: /var/run/secrets/kuma.io/cp-ca/ca.crt + - name: KUMA_DATAPLANE_DRAIN_TIME + value: {{ .Values.egress.drainTime }} + - name: KUMA_DATAPLANE_RUNTIME_TOKEN_PATH + value: /var/run/secrets/kubernetes.io/serviceaccount/token + - name: KUMA_DATAPLANE_PROXY_TYPE + value: "egress" + args: + - run + - --log-level={{ .Values.egress.logLevel | default "info" }} + ports: + - containerPort: 10002 + livenessProbe: + httpGet: + path: "/ready" + port: 9901 + failureThreshold: 12 + initialDelaySeconds: 60 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: "/ready" + port: 9901 + failureThreshold: 12 + initialDelaySeconds: 1 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 3 + resources: {{ toYaml .Values.egress.resources | nindent 12 }} + volumeMounts: +{{- if not .Values.egress.automountServiceAccountToken }} + - mountPath: /var/run/secrets/kubernetes.io/serviceaccount + name: serviceaccount-token + readOnly: true +{{- end }} + - name: control-plane-ca + mountPath: /var/run/secrets/kuma.io/cp-ca + readOnly: true + - name: tmp + mountPath: /tmp + volumes: +{{- if not .Values.egress.automountServiceAccountToken }} + - name: serviceaccount-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + expirationSeconds: 3600 + path: token + - configMap: + name: kube-root-ca.crt + items: + - key: ca.crt + path: ca.crt + - downwardAPI: + items: + - fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + path: namespace +{{- end }} + - name: control-plane-ca + secret: + secretName: {{ include "kuma.controlPlane.tls.general.caSecretName" . }} + items: + - key: ca.crt + path: ca.crt + - name: tmp + emptyDir: {} + {{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/egress-hpa.yaml b/charts/kuma/kuma/2.8.2/templates/egress-hpa.yaml new file mode 100644 index 000000000..8d4284f41 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/egress-hpa.yaml @@ -0,0 +1,24 @@ +{{- if .Values.egress.autoscaling.enabled }} +{{ if .Capabilities.APIVersions.Has "autoscaling/v2" }} +apiVersion: "autoscaling/v2" +{{ else }} +apiVersion: "autoscaling/v1" +{{ end }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "kuma.name" . }}-egress + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.egressLabels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "kuma.name" . }}-egress + minReplicas: {{ .Values.egress.autoscaling.minReplicas }} + maxReplicas: {{ .Values.egress.autoscaling.maxReplicas }} + {{ if .Capabilities.APIVersions.Has "autoscaling/v2" }} + metrics: {{- toYaml .Values.egress.autoscaling.metrics | nindent 4 }} + {{ else }} + targetCPUUtilizationPercentage: {{ .Values.egress.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/egress-pdb.yaml b/charts/kuma/kuma/2.8.2/templates/egress-pdb.yaml new file mode 100644 index 000000000..ee599003b --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/egress-pdb.yaml @@ -0,0 +1,20 @@ +{{ if $.Values.egress.podDisruptionBudget.enabled }} +{{ if .Capabilities.APIVersions.Has "policy/v1" }} +apiVersion: policy/v1 +{{ else if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +{{ fail "pod disruption budgets are not supported by this version of kubernetes" }} +{{ end }} +kind: PodDisruptionBudget +metadata: + name: {{ include "kuma.name" . }}-egress + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.egressLabels" . | nindent 4 }} +spec: + maxUnavailable: {{ .Values.egress.podDisruptionBudget.maxUnavailable }} + selector: + matchLabels: + {{- include "kuma.selectorLabels" . | nindent 6 }} + app: {{ include "kuma.name" . }}-egress +{{ end }} diff --git a/charts/kuma/kuma/2.8.2/templates/egress-rbac.yaml b/charts/kuma/kuma/2.8.2/templates/egress-rbac.yaml new file mode 100644 index 000000000..1b4326fdb --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/egress-rbac.yaml @@ -0,0 +1,18 @@ +{{- if .Values.egress.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "kuma.name" . }}-egress + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.egressLabels" . | nindent 4 }} +{{- with .Values.egress.serviceAccountAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range . }} + - name: {{ . | quote }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/egress-service.yaml b/charts/kuma/kuma/2.8.2/templates/egress-service.yaml new file mode 100644 index 000000000..2127811fe --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/egress-service.yaml @@ -0,0 +1,32 @@ +{{- if .Values.egress.enabled }} +{{- if eq .Values.controlPlane.mode "global" }} +{{ fail "You shouldn't run zoneEgress when running the CP in global" }} +{{- end }} +{{- end }} +{{- if and .Values.egress.enabled .Values.egress.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "kuma.egress.serviceName" . }} + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.egressLabels" . | nindent 4 }} + annotations: + {{- range $key, $value := .Values.egress.service.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + type: {{ .Values.egress.service.type }} + {{- if .Values.egress.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.egress.service.loadBalancerIP }} + {{- end }} + ports: + - port: {{ .Values.egress.service.port }} + protocol: TCP + targetPort: 10002 + {{- if and (eq .Values.egress.service.type "NodePort") .Values.egress.service.nodePort }} + nodePort: {{ .Values.egress.service.nodePort }} + {{- end }} + selector: + app: {{ include "kuma.name" . }}-egress + {{- include "kuma.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/gateway-class.yaml b/charts/kuma/kuma/2.8.2/templates/gateway-class.yaml new file mode 100644 index 000000000..cf1ae305d --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/gateway-class.yaml @@ -0,0 +1,19 @@ +{{- if and (eq .Values.controlPlane.environment "kubernetes") (eq .Values.controlPlane.mode "zone") }} +{{- if .Capabilities.APIVersions.Has "gateway.networking.k8s.io/v1/GatewayClass" }} +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: kuma +spec: + controllerName: "gateways.kuma.io/controller" +{{- else if .Capabilities.APIVersions.Has "gateway.networking.k8s.io/v1beta1/GatewayClass" }} +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: GatewayClass +metadata: + name: kuma +spec: + controllerName: "gateways.kuma.io/controller" +{{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/ingress-deployment.yaml b/charts/kuma/kuma/2.8.2/templates/ingress-deployment.yaml new file mode 100644 index 000000000..65ab4e19a --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/ingress-deployment.yaml @@ -0,0 +1,141 @@ +{{- if .Values.ingress.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "kuma.name" . }}-ingress + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.ingressLabels" . | nindent 4 }} +spec: + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + {{- if not .Values.ingress.autoscaling.enabled }} + replicas: {{ .Values.ingress.replicas }} + {{- end }} + selector: + matchLabels: + {{- include "kuma.selectorLabels" . | nindent 6 }} + app: {{ include "kuma.name" . }}-ingress + template: + metadata: + annotations: + kuma.io/ingress: enabled + {{- range $key, $value := merge .Values.ingress.podAnnotations .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + labels: + {{- include "kuma.ingressLabels" . | nindent 8 }} + spec: + {{- with .Values.ingress.affinity }} + affinity: {{ tpl (toYaml . | nindent 8) $ }} + {{- end }} + {{- with .Values.ingress.topologySpreadConstraints }} + topologySpreadConstraints: {{ tpl (toYaml . | nindent 8) $ }} + {{- end }} + securityContext: + {{- toYaml .Values.ingress.podSecurityContext | trim | nindent 8 }} + serviceAccountName: {{ include "kuma.name" . }}-ingress + automountServiceAccountToken: {{ .Values.ingress.automountServiceAccountToken }} + {{- with .Values.ingress.nodeSelector }} + nodeSelector: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.ingress.tolerations }} + tolerations: + {{ toYaml . | nindent 8 }} + {{- end }} + terminationGracePeriodSeconds: {{ .Values.ingress.terminationGracePeriodSeconds }} + containers: + - name: ingress + image: {{ include "kuma.formatImage" (dict "image" .Values.dataPlane.image "root" $) | quote }} + imagePullPolicy: {{ .Values.dataPlane.image.pullPolicy }} + securityContext: + {{- toYaml .Values.ingress.containerSecurityContext | trim | nindent 12 }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: KUMA_CONTROL_PLANE_URL + value: "https://{{ include "kuma.controlPlane.serviceName" . }}.{{ .Release.Namespace }}:5678" + - name: KUMA_CONTROL_PLANE_CA_CERT_FILE + value: /var/run/secrets/kuma.io/cp-ca/ca.crt + - name: KUMA_DATAPLANE_DRAIN_TIME + value: {{ .Values.ingress.drainTime }} + - name: KUMA_DATAPLANE_RUNTIME_TOKEN_PATH + value: /var/run/secrets/kubernetes.io/serviceaccount/token + - name: KUMA_DATAPLANE_PROXY_TYPE + value: "ingress" + args: + - run + - --log-level={{ .Values.ingress.logLevel | default "info" }} + ports: + - containerPort: 10001 + livenessProbe: + httpGet: + path: "/ready" + port: 9901 + failureThreshold: 12 + initialDelaySeconds: 60 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 3 + readinessProbe: + httpGet: + path: "/ready" + port: 9901 + failureThreshold: 12 + initialDelaySeconds: 1 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 3 + resources: {{ toYaml .Values.ingress.resources | nindent 12 }} + {{ with .Values.ingress.lifecycle}} + lifecycle: {{ . | toYaml | nindent 12 }} + {{ end }} + volumeMounts: +{{- if not .Values.ingress.automountServiceAccountToken }} + - mountPath: /var/run/secrets/kubernetes.io/serviceaccount + name: serviceaccount-token + readOnly: true +{{- end }} + - name: control-plane-ca + mountPath: /var/run/secrets/kuma.io/cp-ca + readOnly: true + - name: tmp + mountPath: /tmp + volumes: +{{- if not .Values.ingress.automountServiceAccountToken }} + - name: serviceaccount-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + expirationSeconds: 3600 + path: token + - configMap: + name: kube-root-ca.crt + items: + - key: ca.crt + path: ca.crt + - downwardAPI: + items: + - fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + path: namespace +{{- end }} + - name: control-plane-ca + secret: + secretName: {{ include "kuma.controlPlane.tls.general.caSecretName" . }} + items: + - key: ca.crt + path: ca.crt + - name: tmp + emptyDir: {} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/ingress-hpa.yaml b/charts/kuma/kuma/2.8.2/templates/ingress-hpa.yaml new file mode 100644 index 000000000..4aaeabe67 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/ingress-hpa.yaml @@ -0,0 +1,24 @@ +{{- if .Values.ingress.autoscaling.enabled }} +{{ if .Capabilities.APIVersions.Has "autoscaling/v2" }} +apiVersion: "autoscaling/v2" +{{ else }} +apiVersion: "autoscaling/v1" +{{ end }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "kuma.name" . }}-ingress + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.ingressLabels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "kuma.name" . }}-ingress + minReplicas: {{ .Values.ingress.autoscaling.minReplicas }} + maxReplicas: {{ .Values.ingress.autoscaling.maxReplicas }} + {{ if .Capabilities.APIVersions.Has "autoscaling/v2" }} + metrics: {{- toYaml .Values.ingress.autoscaling.metrics | nindent 4 }} + {{ else }} + targetCPUUtilizationPercentage: {{ .Values.ingress.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/ingress-pdb.yaml b/charts/kuma/kuma/2.8.2/templates/ingress-pdb.yaml new file mode 100644 index 000000000..639d1b574 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/ingress-pdb.yaml @@ -0,0 +1,20 @@ +{{ if $.Values.ingress.podDisruptionBudget.enabled }} +{{ if .Capabilities.APIVersions.Has "policy/v1" }} +apiVersion: policy/v1 +{{ else if .Capabilities.APIVersions.Has "policy/v1beta1" }} +apiVersion: policy/v1beta1 +{{ else }} +{{ fail "pod disruption budgets are not supported by this version of kubernetes" }} +{{ end }} +kind: PodDisruptionBudget +metadata: + name: {{ include "kuma.name" . }}-ingress + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.ingressLabels" . | nindent 4 }} +spec: + maxUnavailable: {{ .Values.ingress.podDisruptionBudget.maxUnavailable }} + selector: + matchLabels: + {{- include "kuma.selectorLabels" . | nindent 6 }} + app: {{ include "kuma.name" . }}-ingress +{{ end }} diff --git a/charts/kuma/kuma/2.8.2/templates/ingress-rbac.yaml b/charts/kuma/kuma/2.8.2/templates/ingress-rbac.yaml new file mode 100644 index 000000000..e4e1d61ce --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/ingress-rbac.yaml @@ -0,0 +1,18 @@ +{{- if .Values.ingress.enabled }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "kuma.name" . }}-ingress + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.ingressLabels" . | nindent 4 }} +{{- with .Values.ingress.serviceAccountAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} +{{- end }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range . }} + - name: {{ . | quote }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/ingress-service.yaml b/charts/kuma/kuma/2.8.2/templates/ingress-service.yaml new file mode 100644 index 000000000..74a4dde90 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/ingress-service.yaml @@ -0,0 +1,32 @@ +{{- if .Values.ingress.enabled }} +{{- if or (eq .Values.controlPlane.mode "global") (eq .Values.controlPlane.mode "standalone") }} +{{ fail "You shouldn't run zoneIngress when running the CP in global or standalone" }} +{{- end }} +{{- end }} +{{- if and .Values.ingress.enabled .Values.ingress.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "kuma.ingress.serviceName" . }} + namespace: {{ .Release.Namespace }} + labels: {{ include "kuma.ingressLabels" . | nindent 4 }} + annotations: + {{- range $key, $value := .Values.ingress.service.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + type: {{ .Values.ingress.service.type }} + {{- if .Values.ingress.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.ingress.service.loadBalancerIP }} + {{- end }} + ports: + - port: {{ .Values.ingress.service.port }} + protocol: TCP + targetPort: 10001 + {{- if and (eq .Values.ingress.service.type "NodePort") .Values.ingress.service.nodePort }} + nodePort: {{ .Values.ingress.service.nodePort }} + {{- end }} + selector: + app: {{ include "kuma.name" . }}-ingress + {{- include "kuma.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/post-delete-cleanup-ebpf-job.yaml b/charts/kuma/kuma/2.8.2/templates/post-delete-cleanup-ebpf-job.yaml new file mode 100644 index 000000000..aaa3166ff --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/post-delete-cleanup-ebpf-job.yaml @@ -0,0 +1,126 @@ +{{- if and (.Values.experimental.ebpf.enabled) (and (not .Values.cni.enabled) (not .Values.noHelmHooks) (eq .Values.controlPlane.environment "kubernetes")) }} + {{- $serviceAccountName := printf "%s-cleanup-node-ebpf-job" (include "kuma.name" .) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "post-delete" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range . }} + - name: {{ . | quote }} + {{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "kuma.name" . }}-cleanup-node-ebpf-job + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "post-delete" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +rules: + - apiGroups: [""] + resources: + - nodes + verbs: + - list + - apiGroups: [""] + resources: + - pods + verbs: + - watch + - delete + - deletecollection + - apiGroups: ["batch"] + resources: + - jobs + verbs: + - watch + - create + - delete + - deletecollection +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kuma.name" . }}-cleanup-node-ebpf-job + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "post-delete" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kuma.name" . }}-cleanup-node-ebpf-job +subjects: + - kind: ServiceAccount + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "kuma.name" . }}-cleanup-node-ebpf-job + namespace: {{ .Release.Namespace }} + labels: + {{ include "kuma.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": "post-delete" + {{/* Ensure the job is created after the RBAC resources */}} + "helm.sh/hook-weight": "5" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" +spec: + template: + metadata: + name: {{ template "kuma.name" . }}-cleanup-node-ebpf-job + labels: + {{ include "kuma.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + {{- with .Values.hooks.nodeSelector }} + nodeSelector: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.hooks.tolerations }} + tolerations: + {{ toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + {{- if .Values.hooks.ebpfCleanup.podSecurityContext }} + securityContext: + {{ toYaml .Values.hooks.ebpfCleanup.podSecurityContext | trim | nindent 8 }} + {{- end }} + containers: + - name: post-delete-job + image: {{ include "kuma.formatImage" (dict "image" .Values.dataPlane.initImage "root" $) | quote }} + {{- if .Values.hooks.ebpfCleanup.containerSecurityContext }} + securityContext: + {{ toYaml .Values.hooks.ebpfCleanup.containerSecurityContext | trim | nindent 12 }} + {{- end }} + resources: + requests: + cpu: "20m" + memory: "20Mi" + limits: + cpu: "40m" + memory: "40Mi" + command: + - 'kumactl' + - 'uninstall' + - 'ebpf' + - '--cleanup-image-registry' + - {{ .Values.global.image.registry }} + - '--cleanup-image-repository' + - {{ .Values.dataPlane.initImage.repository }} + {{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/pre-delete-webhooks.yaml b/charts/kuma/kuma/2.8.2/templates/pre-delete-webhooks.yaml new file mode 100644 index 000000000..e6948af2f --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/pre-delete-webhooks.yaml @@ -0,0 +1,109 @@ +{{- if and (eq .Values.controlPlane.environment "kubernetes") (not .Values.noHelmHooks) }} +# HELM first deletes RBAC of Kuma, then it tries to delete Secrets. We've got validating webhook on Secrets. +# But even that the policy of this webhook is Ignore, it fails because Kuma does not have permission to access Secrets anymore. +# Therefore we first need to delete webhook so we can delete the rest of the deployment +{{- $serviceAccountName := printf "%s-pre-delete-job" (include "kuma.name" .) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "pre-delete" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range . }} + - name: {{ . | quote }} + {{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "kuma.name" . }}-pre-delete-job + annotations: + "helm.sh/hook": "pre-delete" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +rules: + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + resourceNames: + - {{ include "kuma.name" . }}-validating-webhook-configuration + verbs: + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kuma.name" . }}-pre-delete-job + annotations: + "helm.sh/hook": "pre-delete" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kuma.name" . }}-pre-delete-job +subjects: + - kind: ServiceAccount + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "kuma.name" . }}-delete-webhook + namespace: {{ .Release.Namespace }} + labels: + {{ include "kuma.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": "pre-delete" + {{/* Ensure the job is created after the RBAC resources */}} + "helm.sh/hook-weight": "5" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" +spec: + template: + metadata: + name: {{ template "kuma.name" . }}-delete-webhook + labels: + {{ include "kuma.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + {{- with .Values.hooks.nodeSelector }} + nodeSelector: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.hooks.tolerations }} + tolerations: + {{ toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + securityContext: + {{- toYaml .Values.hooks.podSecurityContext | trim | nindent 8 }} + containers: + - name: pre-delete-job + image: "{{ .Values.kubectl.image.registry }}/{{ .Values.kubectl.image.repository }}:{{ .Values.kubectl.image.tag }}" + command: + - 'kubectl' + - 'delete' + - 'ValidatingWebhookConfiguration' + - '--ignore-not-found' + - {{ include "kuma.name" . }}-validating-webhook-configuration + securityContext: + {{- toYaml (mergeOverwrite (dict "runAsUser" 65534) .Values.hooks.containerSecurityContext) | trim | nindent 12 }} + resources: + requests: + cpu: "100m" + memory: "256Mi" + limits: + cpu: "100m" + memory: "256Mi" +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/pre-install-patch-namespace-job.yaml b/charts/kuma/kuma/2.8.2/templates/pre-install-patch-namespace-job.yaml new file mode 100644 index 000000000..a84d7accf --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/pre-install-patch-namespace-job.yaml @@ -0,0 +1,124 @@ +{{- if and ( .Values.noHelmHooks ) (eq .Values.controlPlane.environment "kubernetes") }} + {{- $errorMessage := ".Values.noHelmHooks is set. You must manually create and label the system namespace with kuma.io/system-namespace: \"true\" before installing or upgrading the chart" }} + {{- $systemNamespace := (lookup "v1" "Namespace" "" .Release.Namespace) }} + {{- if not $systemNamespace }} + {{- fail $errorMessage }} + {{- end }} + {{- $systemNamespaceLabels := ($systemNamespace).metadata.labels }} + {{- if ne (get $systemNamespaceLabels "kuma.io/system-namespace") "true" }} + {{- fail $errorMessage }} + {{- end }} +{{- else}} + {{- if .Values.patchSystemNamespace }} + {{- $serviceAccountName := printf "%s-patch-ns-job" (include "kuma.name" .) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "pre-install" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- range . }} + - name: {{ . | quote }} + {{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "kuma.name" . }}-patch-ns-job + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "pre-install" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - namespaces + resourceNames: + - {{ .Release.Namespace }} + verbs: + - get + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kuma.name" . }}-patch-ns-job + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "pre-install" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kuma.name" . }}-patch-ns-job +subjects: + - kind: ServiceAccount + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "kuma.name" . }}-patch-ns + namespace: {{ .Release.Namespace }} + labels: + {{ include "kuma.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": "pre-install" + {{/* Ensure the job is created after the RBAC resources */}} + "helm.sh/hook-weight": "5" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" +spec: + template: + metadata: + name: {{ template "kuma.name" . }}-patch-ns-script + labels: + {{ include "kuma.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + {{- with .Values.hooks.nodeSelector }} + nodeSelector: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.hooks.tolerations }} + tolerations: + {{ toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + securityContext: + {{- toYaml .Values.hooks.podSecurityContext | trim | nindent 8 }} + containers: + - name: pre-install-job + image: "{{ .Values.kubectl.image.registry }}/{{ .Values.kubectl.image.repository }}:{{ .Values.kubectl.image.tag }}" + securityContext: + {{- toYaml (mergeOverwrite (dict "runAsUser" 65534) .Values.hooks.containerSecurityContext) | trim | nindent 12 }} + resources: + requests: + cpu: "100m" + memory: "256Mi" + limits: + cpu: "100m" + memory: "256Mi" + command: + - 'kubectl' + - 'patch' + - 'namespace' + - {{ .Release.Namespace | quote }} + - '--type' + - 'merge' + - '--patch' + - '{ "metadata": { "labels": { "kuma.io/system-namespace": "true" } } }' + {{- end }} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/templates/pre-upgrade-install-crds-job.yaml b/charts/kuma/kuma/2.8.2/templates/pre-upgrade-install-crds-job.yaml new file mode 100644 index 000000000..8fadf1722 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/templates/pre-upgrade-install-crds-job.yaml @@ -0,0 +1,171 @@ +{{- if (and .Values.installCrdsOnUpgrade.enabled (and (not .Values.noHelmHooks) (eq .Values.controlPlane.environment "kubernetes"))) }} + {{ $hook := "pre-upgrade,pre-install" }} + {{- $serviceAccountName := printf "%s-install-crds" (include "kuma.name" .) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "{{ $hook }}" + "helm.sh/hook-weight": "-1" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +{{- with concat .Values.installCrdsOnUpgrade.imagePullSecrets .Values.global.imagePullSecrets | uniq }} +imagePullSecrets: + {{- range . }} + - name: {{ . | quote }} + {{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "kuma.name" . }}-install-crds + annotations: + "helm.sh/hook": "{{ $hook }}" + "helm.sh/hook-weight": "-1" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +rules: + - apiGroups: + - "apiextensions.k8s.io" + resources: + - customresourcedefinitions + verbs: + - create + - patch + - update + - list + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kuma.name" . }}-install-crds + annotations: + "helm.sh/hook": "{{ $hook }}" + "helm.sh/hook-weight": "-1" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded,hook-failed" + labels: + {{- include "kuma.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kuma.name" . }}-install-crds +subjects: + - kind: ServiceAccount + name: {{ $serviceAccountName }} + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "kuma.name" . }}-install-crds-scripts + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": "{{ $hook }}" + "helm.sh/hook-weight": "-1" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" + labels: + {{- include "kuma.labels" . | nindent 4 }} +data: + install_crds.sh: | + #!/usr/bin/env sh + set -e + + if [ -s /kuma/crds/crds.yaml ]; then + echo "/kuma/crds/crds.yaml found and is not empty, adding crds" + kubectl apply -f /kuma/crds/crds.yaml + else + echo "/kuma/crds/crds.yaml not found or empty, it looks like there is no crds to install" + fi + save_crds.sh: | + set -e + + crds="$(kumactl install crds --no-config)" + + if [ -n "${crds}" ]; then + echo "found crds - saving to /kuma/crds/crds.yaml" + echo "${crds}" > /kuma/crds/crds.yaml + fi +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "kuma.name" . }}-install-crds + namespace: {{ .Release.Namespace }} + labels: + {{ include "kuma.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": "{{ $hook }}" + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" +spec: + template: + metadata: + name: {{ template "kuma.name" . }}-install-crds-job + labels: + {{ include "kuma.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ $serviceAccountName }} + {{- with .Values.hooks.nodeSelector }} + nodeSelector: + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.hooks.tolerations }} + tolerations: + {{ toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + securityContext: + {{- toYaml .Values.hooks.podSecurityContext | trim | nindent 8 }} + containers: + - name: pre-upgrade-job + image: "{{ .Values.kubectl.image.registry }}/{{ .Values.kubectl.image.repository }}:{{ .Values.kubectl.image.tag }}" + securityContext: + {{- toYaml (mergeOverwrite (dict "runAsUser" 65534) .Values.hooks.containerSecurityContext) | trim | nindent 12 }} + resources: + requests: + cpu: "100m" + memory: "256Mi" + limits: + cpu: "100m" + memory: "256Mi" + command: ["/kuma/scripts/install_crds.sh"] + volumeMounts: + - mountPath: /kuma/crds + name: crds + readOnly: true + - mountPath: /kuma/scripts + name: scripts + readOnly: true + initContainers: + - name: pre-upgrade-job-init + image: {{ include "kuma.formatImage" (dict "image" .Values.kumactl.image "root" $) | quote }} + securityContext: + {{- toYaml .Values.hooks.containerSecurityContext | trim | nindent 12 }} + resources: + requests: + cpu: "100m" + memory: "256Mi" + limits: + cpu: "100m" + memory: "256Mi" + volumeMounts: + - mountPath: /kuma/crds + name: crds + - mountPath: /kuma/scripts + name: scripts + readOnly: true + command: ["sh", "-c"] + args: ["/kuma/scripts/save_crds.sh"] + volumes: + - name: scripts + configMap: + name: {{ include "kuma.name" . }}-install-crds-scripts + defaultMode: 0755 + - name: crds + emptyDir: {} +{{- end }} diff --git a/charts/kuma/kuma/2.8.2/values.yaml b/charts/kuma/kuma/2.8.2/values.yaml new file mode 100644 index 000000000..bcd67e454 --- /dev/null +++ b/charts/kuma/kuma/2.8.2/values.yaml @@ -0,0 +1,748 @@ +global: + image: + # -- Default registry for all Kuma Images + registry: "docker.io/kumahq" + # -- The default tag for all Kuma images, which itself defaults to .Chart.AppVersion + tag: + # -- Add `imagePullSecrets` to all the service accounts used for Kuma components + imagePullSecrets: [] + +# -- Whether to patch the target namespace with the system label +patchSystemNamespace: true + +installCrdsOnUpgrade: + # -- Whether install new CRDs before upgrade (if any were introduced with the new version of Kuma) + enabled: true + # -- The `imagePullSecrets` to attach to the Service Account running CRD installation. + # This field will be deprecated in a future release, please use .global.imagePullSecrets + imagePullSecrets: [] + +# -- Whether to disable all helm hooks +noHelmHooks: false + +# -- Whether to restart control-plane by calculating a new checksum for the secret +restartOnSecretChange: true + +controlPlane: + # -- Environment that control plane is run in, useful when running universal global control plane on k8s + environment: "kubernetes" + + # -- Labels to add to resources in addition to default labels + extraLabels: {} + + # -- Kuma CP log level: one of off,info,debug + logLevel: "info" + + # -- Kuma CP log output path: Defaults to /dev/stdout + logOutputPath: "" + + # -- Kuma CP modes: one of zone,global + mode: "zone" + + # -- (string) Kuma CP zone, if running multizone + zone: + + # -- Only used in `zone` mode + kdsGlobalAddress: "" + + # -- Number of replicas of the Kuma CP. Ignored when autoscaling is enabled + replicas: 1 + + # -- Minimum number of seconds for which a newly created pod should be ready for it to be considered available. + minReadySeconds: 0 + + # -- Annotations applied only to the `Deployment` resource + deploymentAnnotations: {} + + # -- Annotations applied only to the `Pod` resource + podAnnotations: {} + + # Horizontal Pod Autoscaling configuration + autoscaling: + # -- Whether to enable Horizontal Pod Autoscaling, which requires the [Metrics Server](https://github.com/kubernetes-sigs/metrics-server) in the cluster + enabled: false + + # -- The minimum CP pods to allow + minReplicas: 2 + # -- The max CP pods to scale to + maxReplicas: 5 + + # -- For clusters that don't support autoscaling/v2, autoscaling/v1 is used + targetCPUUtilizationPercentage: 80 + # -- For clusters that do support autoscaling/v2, use metrics + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 80 + + # -- Node selector for the Kuma Control Plane pods + nodeSelector: + kubernetes.io/os: linux + + # -- Tolerations for the Kuma Control Plane pods + tolerations: [] + + podDisruptionBudget: + # -- Whether to create a pod disruption budget + enabled: false + # -- The maximum number of unavailable pods allowed by the budget + maxUnavailable: 1 + + # -- Affinity placement rule for the Kuma Control Plane pods. + # This is rendered as a template, so you can reference other helm variables or includes. + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + # These match the selector labels used on the deployment. + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ include "kuma.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app + operator: In + values: + - '{{ include "kuma.name" . }}-control-plane' + topologyKey: kubernetes.io/hostname + + # -- Topology spread constraints rule for the Kuma Control Plane pods. + # This is rendered as a template, so you can use variables to generate match labels. + topologySpreadConstraints: + + # -- Failure policy of the mutating webhook implemented by the Kuma Injector component + injectorFailurePolicy: Fail + + service: + apiServer: + http: + # -- Port on which Http api server Service is exposed on Node for service of type NodePort + nodePort: 30681 + https: + # -- Port on which Https api server Service is exposed on Node for service of type NodePort + nodePort: 30682 + + # -- Whether to create a service resource. + enabled: true + + # -- (string) Optionally override of the Kuma Control Plane Service's name + name: + + # -- Service type of the Kuma Control Plane + type: ClusterIP + + # -- Annotations to put on the Kuma Control Plane + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "5680" + + # Kuma API and GUI ingress settings. Useful if you want to expose the + # API and GUI of Kuma outside the k8s cluster. + ingress: + # -- Install K8s Ingress resource that exposes GUI and API + enabled: false + # -- IngressClass defines which controller will implement the resource + ingressClassName: + # -- Ingress hostname + hostname: + # -- Map of ingress annotations. + annotations: {} + # -- Ingress path. + path: / + # -- Each path in an Ingress is required to have a corresponding path type. (ImplementationSpecific/Exact/Prefix) + pathType: ImplementationSpecific + # -- Port from kuma-cp to use to expose API and GUI. Switch to 5682 to expose TLS port + servicePort: 5681 + + globalZoneSyncService: + # -- Whether to create a k8s service for the global zone sync + # service. It will only be created when enabled and deploying the global + # control plane. + enabled: true + # -- Service type of the Global-zone sync + type: LoadBalancer + # -- (string) Optionally specify IP to be used by cloud provider when configuring load balancer + loadBalancerIP: + # -- Optionally specify allowed source ranges that can access the load balancer + loadBalancerSourceRanges: [] + # -- Additional annotations to put on the Global Zone Sync Service + annotations: { } + # -- Port on which Global Zone Sync Service is exposed on Node for service of type NodePort + nodePort: 30685 + # -- Port on which Global Zone Sync Service is exposed + port: 5685 + # -- Protocol of the Global Zone Sync service port + protocol: grpc + + defaults: + # -- Whether to skip creating the default Mesh + skipMeshCreation: false + + # -- Whether to automountServiceAccountToken for cp. Optionally set to false + automountServiceAccountToken: true + + # -- Optionally override the resource spec + resources: + requests: + cpu: 500m + memory: 256Mi + limits: + memory: 256Mi + + # -- Pod lifecycle settings (useful for adding a preStop hook, when + # using AWS ALB or NLB) + lifecycle: {} + + # -- Number of seconds to wait before force killing the pod. Make sure to + # update this if you add a preStop hook. + terminationGracePeriodSeconds: 30 + + # TLS for various servers + tls: + general: + # -- Secret that contains tls.crt, tls.key [and ca.crt when no + # controlPlane.tls.general.caSecretName specified] for protecting + # Kuma in-cluster communication + secretName: "" + # -- Secret that contains ca.crt that was used to sign cert for protecting + # Kuma in-cluster communication (ca.crt present in this secret + # have precedence over the one provided in the controlPlane.tls.general.secretName) + caSecretName: "" + # -- Base64 encoded CA certificate (the same as in controlPlane.tls.general.secret#ca.crt) + caBundle: "" + apiServer: + # -- Secret that contains tls.crt, tls.key for protecting Kuma API on HTTPS + secretName: "" + # -- Secret that contains list of .pem certificates that can access admin endpoints of Kuma API on HTTPS + clientCertsSecretName: "" + # - if not creating the global control plane, then do nothing + # - if secretName is empty and create is false, then do nothing + # - if secretName is non-empty and create is false, then use the secret made outside of helm with the name secretName + # - if secretName is empty and create is true, then create a secret with a default name and use it + # - if secretName is non-empty and create is true, then create the secret using the provided name + kdsGlobalServer: + # -- Name of the K8s TLS Secret resource. If you set this and don't set + # create=true, you have to create the secret manually. + secretName: "" + # -- Whether to create the TLS secret in helm. + create: false + # -- The TLS certificate to offer. + cert: "" + # -- The TLS key to use. + key: "" + # - if not creating the zonal control plane, then do nothing + # - if secretName is empty and create is false, then do nothing + # - if secretName is non-empty and create is false, then use the secret made outside of helm with the name secretName + # - if secretName is empty and create is true, then create a secret with a default name and use it + # - if secretName is non-empty and create is true, then create the secret using the provided name + kdsZoneClient: + # -- Name of the K8s Secret resource that contains ca.crt which was + # used to sign the certificate of KDS Global Server. If you set this + # and don't set create=true, you have to create the secret manually. + secretName: "" + # -- Whether to create the TLS secret in helm. + create: false + # -- CA bundle that was used to sign the certificate of KDS Global Server. + cert: "" + # -- If true, TLS cert of the server is not verified. + skipVerify: false + + # -- Annotations to add for Control Plane's Service Account + serviceAccountAnnotations: { } + + image: + # -- Kuma CP ImagePullPolicy + pullPolicy: IfNotPresent + # -- Kuma CP image repository + repository: "kuma-cp" + # -- Kuma CP Image tag. When not specified, the value is copied from global.tag + tag: + + # -- (object with { Env: string, Secret: string, Key: string }) Secrets to add as environment variables, + # where `Env` is the name of the env variable, + # `Secret` is the name of the Secret, + # and `Key` is the key of the Secret value to use + secrets: + # someSecret: + # Secret: some-secret + # Key: secret_key + # Env: SOME_SECRET + + # -- Additional environment variables that will be passed to the control plane + envVars: { } + + # -- Additional config maps to mount into the control plane, with optional inline values + extraConfigMaps: [ ] +# - name: extra-config +# mountPath: /etc/extra-config +# readOnly: true +# values: +# extra-config-key: | +# extra-config-value + + # -- (object with { name: string, mountPath: string, readOnly: string }) Additional secrets to mount into the control plane, + # where `Env` is the name of the env variable, + # `Secret` is the name of the Secret, + # and `Key` is the key of the Secret value to use + extraSecrets: + # extraConfig: + # name: extra-config + # mountPath: /etc/extra-config + # readOnly: true + + webhooks: + validator: + # -- Additional rules to apply on Kuma validator webhook. Useful when building custom policy on top of Kuma. + additionalRules: "" + ownerReference: + # -- Additional rules to apply on Kuma owner reference webhook. Useful when building custom policy on top of Kuma. + additionalRules: "" + + # -- Specifies if the deployment should be started in hostNetwork mode. + hostNetwork: false + # -- Define a new server port for the admission controller. Recommended to set in combination with + # hostNetwork to prevent multiple port bindings on the same port (like Calico in AWS EKS). + admissionServerPort: 5443 + + # -- Security context at the pod level for control plane. + podSecurityContext: + runAsNonRoot: true + + # -- Security context at the container level for control plane. + containerSecurityContext: + readOnlyRootFilesystem: true + + # -- If true, then control plane can support TLS secrets for builtin gateway outside of mesh system namespace. + # The downside is that control plane requires permission to read Secrets in all namespaces. + supportGatewaySecretsInAllNamespaces: false + +cni: + # -- Install Kuma with CNI instead of proxy init container + enabled: false + # -- Install CNI in chained mode + chained: false + # -- Set the CNI install directory + netDir: /etc/cni/multus/net.d + # -- Set the CNI bin directory + binDir: /var/lib/cni/bin + # -- Set the CNI configuration name + confName: kuma-cni.conf + # -- CNI log level: one of off,info,debug + logLevel: info + # -- Node Selector for the CNI pods + nodeSelector: + kubernetes.io/os: linux + # -- Tolerations for the CNI pods + tolerations: [] + # -- Additional pod annotations + podAnnotations: { } + # -- Set the CNI namespace + namespace: kube-system + + image: + # -- CNI image repository + repository: "kuma-cni" + # -- CNI image tag - defaults to .Chart.AppVersion + tag: + # -- CNI image pull policy + imagePullPolicy: IfNotPresent + + # -- it's only useful in tests to trigger a possible race condition + delayStartupSeconds: 0 + + # -- use new CNI (experimental) + experimental: + imageEbpf: + # -- CNI experimental eBPF image registry + registry: "docker.io/kumahq" + # -- CNI experimental eBPF image repository + repository: "merbridge" + # -- CNI experimental eBPF image tag + tag: "0.8.5" + + resources: + requests: + cpu: 100m + memory: 100Mi + limits: + memory: 100Mi + + # -- Security context at the pod level for cni + podSecurityContext: {} + + # -- Security context at the container level for cni + containerSecurityContext: + readOnlyRootFilesystem: true + runAsNonRoot: false + runAsUser: 0 + runAsGroup: 0 + +dataPlane: + # -- If true, then turn on CoreDNS query logging + dnsLogging: false + image: + # -- The Kuma DP image repository + repository: "kuma-dp" + # -- Kuma DP ImagePullPolicy + pullPolicy: IfNotPresent + # -- Kuma DP Image Tag. When not specified, the value is copied from global.tag + tag: + + initImage: + # -- The Kuma DP init image repository + repository: "kuma-init" + # -- Kuma DP init image tag When not specified, the value is copied from global.tag + tag: + +ingress: + # -- If true, it deploys Ingress for cross cluster communication + enabled: false + + # -- Labels to add to resources, in addition to default labels + extraLabels: {} + + # -- Time for which old listener will still be active as draining + drainTime: 30s + + # -- Number of replicas of the Ingress. Ignored when autoscaling is enabled. + replicas: 1 + + # -- Log level for ingress (available values: off|info|debug) + logLevel: info + + # -- Define the resources to allocate to mesh ingress + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 1000m + memory: 512Mi + + # -- Pod lifecycle settings (useful for adding a preStop hook, when + # using AWS ALB or NLB) + lifecycle: {} + + # -- Number of seconds to wait before force killing the pod. Make sure to + # update this if you add a preStop hook. + terminationGracePeriodSeconds: 40 + + # Horizontal Pod Autoscaling configuration + autoscaling: + # -- Whether to enable Horizontal Pod Autoscaling, which requires the [Metrics Server](https://github.com/kubernetes-sigs/metrics-server) in the cluster + enabled: false + + # -- The minimum CP pods to allow + minReplicas: 2 + # -- The max CP pods to scale to + maxReplicas: 5 + + # -- For clusters that don't support autoscaling/v2, autoscaling/v1 is used + targetCPUUtilizationPercentage: 80 + # -- For clusters that do support autoscaling/v2, use metrics + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 80 + + service: + # -- Whether to create a Service resource. + enabled: true + # -- Service type of the Ingress + type: LoadBalancer + # -- (string) Optionally specify IP to be used by cloud provider when configuring load balancer + loadBalancerIP: + # -- Additional annotations to put on the Ingress service + annotations: { } + # -- Port on which Ingress is exposed + port: 10001 + # -- Port on which service is exposed on Node for service of type NodePort + nodePort: + # -- Additional pod annotations (deprecated favor `podAnnotations`) + annotations: { } + # -- Additional pod annotations + podAnnotations: { } + # -- Node Selector for the Ingress pods + nodeSelector: + kubernetes.io/os: linux + # -- Tolerations for the Ingress pods + tolerations: [] + podDisruptionBudget: + # -- Whether to create a pod disruption budget + enabled: false + # -- The maximum number of unavailable pods allowed by the budget + maxUnavailable: 1 + + # -- Affinity placement rule for the Kuma Ingress pods + # This is rendered as a template, so you can reference other helm variables + # or includes. + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + # These match the selector labels used on the deployment. + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ include "kuma.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app + operator: In + values: + - kuma-ingress + topologyKey: kubernetes.io/hostname + + # -- Topology spread constraints rule for the Kuma Mesh Ingress pods. + # This is rendered as a template, so you can use variables to generate match labels. + topologySpreadConstraints: + + # -- Security context at the pod level for ingress + podSecurityContext: + runAsNonRoot: true + runAsUser: 5678 + runAsGroup: 5678 + + # -- Security context at the container level for ingress + containerSecurityContext: + readOnlyRootFilesystem: true + + # -- Annotations to add for Control Plane's Service Account + serviceAccountAnnotations: { } + # -- Whether to automountServiceAccountToken for cp. Optionally set to false + automountServiceAccountToken: true + +egress: + # -- If true, it deploys Egress for cross cluster communication + enabled: false + # -- Labels to add to resources, in addition to the default labels. + extraLabels: {} + # -- Time for which old listener will still be active as draining + drainTime: 30s + # -- Number of replicas of the Egress. Ignored when autoscaling is enabled. + replicas: 1 + + # -- Log level for egress (available values: off|info|debug) + logLevel: info + + # Horizontal Pod Autoscaling configuration + autoscaling: + # -- Whether to enable Horizontal Pod Autoscaling, which requires the [Metrics Server](https://github.com/kubernetes-sigs/metrics-server) in the cluster + enabled: false + + # -- The minimum CP pods to allow + minReplicas: 2 + # -- The max CP pods to scale to + maxReplicas: 5 + + # -- For clusters that don't support autoscaling/v2, autoscaling/v1 is used + targetCPUUtilizationPercentage: 80 + # -- For clusters that do support autoscaling/v2, use metrics + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 80 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 1000m + memory: 512Mi + + service: + # -- Whether to create the service object + enabled: true + # -- Service type of the Egress + type: ClusterIP + # -- (string) Optionally specify IP to be used by cloud provider when configuring load balancer + loadBalancerIP: + # -- Additional annotations to put on the Egress service + annotations: { } + # -- Port on which Egress is exposed + port: 10002 + # -- Port on which service is exposed on Node for service of type NodePort + nodePort: + # -- Additional pod annotations (deprecated favor `podAnnotations`) + annotations: { } + # -- Additional pod annotations + podAnnotations: { } + # -- Node Selector for the Egress pods + nodeSelector: + kubernetes.io/os: linux + # -- Tolerations for the Egress pods + tolerations: [] + podDisruptionBudget: + # -- Whether to create a pod disruption budget + enabled: false + # -- The maximum number of unavailable pods allowed by the budget + maxUnavailable: 1 + + # -- Affinity placement rule for the Kuma Egress pods. + # This is rendered as a template, so you can reference other helm variables or includes. + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + # These match the selector labels used on the deployment. + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - '{{ include "kuma.name" . }}' + - key: app.kubernetes.io/instance + operator: In + values: + - '{{ .Release.Name }}' + - key: app + operator: In + values: + - kuma-egress + topologyKey: kubernetes.io/hostname + + # -- Topology spread constraints rule for the Kuma Egress pods. + # This is rendered as a template, so you can use variables to generate match labels. + topologySpreadConstraints: + + # -- Security context at the pod level for egress + podSecurityContext: + runAsNonRoot: true + runAsUser: 5678 + runAsGroup: 5678 + + # -- Security context at the container level for egress + containerSecurityContext: + readOnlyRootFilesystem: true + + # -- Annotations to add for Control Plane's Service Account + serviceAccountAnnotations: { } + # -- Whether to automountServiceAccountToken for cp. Optionally set to false + automountServiceAccountToken: true + +kumactl: + image: + # -- The kumactl image repository + repository: kumactl + # -- The kumactl image tag. When not specified, the value is copied from global.tag + tag: + +kubectl: + image: + # -- The kubectl image registry + registry: docker.io + # -- The kubectl image repository + repository: bitnami/kubectl + # -- The kubectl image tag + tag: "1.27.5" +hooks: + # -- Node selector for the HELM hooks + nodeSelector: + kubernetes.io/os: linux + # -- Tolerations for the HELM hooks + tolerations: [] + # -- Security context at the pod level for crd/webhook/ns + podSecurityContext: + runAsNonRoot: true + + # -- Security context at the container level for crd/webhook/ns + containerSecurityContext: + readOnlyRootFilesystem: true + + # -- ebpf-cleanup hook needs write access to the root filesystem to clean ebpf programs + # Changing below values will potentially break ebpf cleanup completely, + # so be cautious when doing so. + ebpfCleanup: + # -- Security context at the pod level for crd/webhook/cleanup-ebpf + podSecurityContext: + runAsNonRoot: false + # -- Security context at the container level for crd/webhook/cleanup-ebpf + containerSecurityContext: + readOnlyRootFilesystem: false + +experimental: + # Configuration for the experimental ebpf mode for transparent proxy + ebpf: + # -- If true, ebpf will be used instead of using iptables to install/configure transparent proxy + enabled: false + # -- Name of the environmental variable which will contain the IP address of a pod + instanceIPEnvVarName: INSTANCE_IP + # -- Path where BPF file system should be mounted + bpffsPath: /sys/fs/bpf + # -- Host's cgroup2 path + cgroupPath: /sys/fs/cgroup + # -- Name of the network interface which TC programs should be attached to, we'll try to automatically determine it if empty + tcAttachIface: "" + # -- Path where compiled eBPF programs which will be installed can be found + programsSourcePath: /tmp/kuma-ebpf + # -- If false, it uses legacy API for resource synchronization + deltaKds: true + # -- If true, enable native Kubernetes sidecars. This requires at least + # Kubernetes v1.29 + sidecarContainers: false + +# Postgres' settings for universal control plane on k8s +postgres: + # -- Postgres port, password should be provided as a secret reference in "controlPlane.secrets" + # with the Env value "KUMA_STORE_POSTGRES_PASSWORD". + # Example: + # controlPlane: + # secrets: + # - Secret: postgres-postgresql + # Key: postgresql-password + # Env: KUMA_STORE_POSTGRES_PASSWORD + port: "5432" + # TLS settings + tls: + # -- Mode of TLS connection. Available values are: "disable", "verifyNone", "verifyCa", "verifyFull" + mode: disable # ENV: KUMA_STORE_POSTGRES_TLS_MODE + # -- Whether to disable SNI the postgres `sslsni` option. + disableSSLSNI: false # ENV: KUMA_STORE_POSTGRES_TLS_DISABLE_SSLSNI + # -- Secret name that contains the ca.crt + caSecretName: + # -- Secret name that contains the client tls.crt, tls.key + secretName: + +# @ignored for helm-docs +plugins: + resources: + hostnamegenerators: true + meshexternalservices: true + meshservices: true + policies: + meshaccesslogs: true + meshcircuitbreakers: true + meshfaultinjections: true + meshhealthchecks: true + meshhttproutes: true + meshloadbalancingstrategies: true + meshmetrics: true + meshpassthroughs: true + meshproxypatches: true + meshratelimits: true + meshretries: true + meshtcproutes: true + meshtimeouts: true + meshtraces: true + meshtrafficpermissions: true diff --git a/charts/minio/minio-operator/6.0.1/.helmignore b/charts/minio/minio-operator/6.0.1/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/minio/minio-operator/6.0.1/Chart.yaml b/charts/minio/minio-operator/6.0.1/Chart.yaml new file mode 100644 index 000000000..6a2c155d8 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/Chart.yaml @@ -0,0 +1,23 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Minio Operator + catalog.cattle.io/kube-version: '>=1.19-0' + catalog.cattle.io/release-name: minio-operator +apiVersion: v2 +appVersion: v6.0.1 +description: A Helm chart for MinIO Operator +home: https://min.io +icon: file://assets/icons/minio-operator.png +keywords: +- storage +- object-storage +- S3 +kubeVersion: '>=1.19-0' +maintainers: +- email: dev@minio.io + name: MinIO, Inc +name: minio-operator +sources: +- https://github.com/minio/operator +type: application +version: 6.0.1 diff --git a/charts/minio/minio-operator/6.0.1/README.md b/charts/minio/minio-operator/6.0.1/README.md new file mode 100644 index 000000000..c7e73ec3e --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/README.md @@ -0,0 +1,45 @@ +# MinIO ![license](https://img.shields.io/badge/license-AGPL%20V3-blue) + +[MinIO](https://min.io) is a High Performance Object Storage released under GNU AGPLv3 or later. It is API compatible +with Amazon S3 cloud storage service. Use MinIO to build high performance infrastructure for machine learning, analytics +and application data workloads. + +For more detailed documentation please visit [here](https://docs.minio.io/) + +Introduction +------------ + +This chart bootstraps MinIO Operator on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +Configure MinIO Helm repo +-------------------- + +```bash +helm repo add minio https://operator.min.io/ +``` + +Installing the Chart +-------------------- + +Install this chart using: + +```bash +helm install \ + --namespace minio-operator \ + --create-namespace \ + minio-operator minio/operator +``` + +The command deploys MinIO Operator on the Kubernetes cluster in the default configuration. + +Creating a Tenant +----------------- + +Once the MinIO Operator Chart is successfully installed, create a MinIO Tenant using: + +```bash +helm install --namespace tenant-ns \ + --create-namespace tenant minio/tenant +``` + +This creates a 4 Node MinIO Tenant (cluster). To change the default values, take a look at various [values.yaml](https://github.com/minio/operator/blob/master/helm/tenant/values.yaml). diff --git a/charts/minio/minio-operator/6.0.1/app-readme.md b/charts/minio/minio-operator/6.0.1/app-readme.md new file mode 100644 index 000000000..ac0f1294a --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/app-readme.md @@ -0,0 +1,78 @@ +# MinIO Operator + +MinIO is a Kubernetes-native high performance object store with an S3-compatible API. The +MinIO Kubernetes Operator supports deploying MinIO Tenants onto private and public +cloud infrastructures ("Hybrid" Cloud). + +## Procedure + +### 1) Verify installation the MinIO Operator +Run the following command to verify the status of the Operator: + +```sh +kubectl get pods -n minio-operator +``` + +The output resembles the following: + +```sh +NAME READY STATUS RESTARTS AGE +console-6b6cf8946c-9cj25 1/1 Running 0 99s +minio-operator-69fd675557-lsrqg 1/1 Running 0 99s +``` + +The `console-*` pod runs the MinIO Operator Console, a graphical user +interface for creating and managing MinIO Tenants. + +The `minio-operator-*` pod runs the MinIO Operator itself. + +### 2) Access the Operator Console + +Get the service-account token to access the UI: + +```sh +kubectl -n minio-operator get secret $(kubectl -n minio-operator get serviceaccount console-sa -o jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64 --decode +``` + +Run the following command to create a local proxy to the MinIO Operator +Console: + +```sh +kubectl -n minio-operator port-forward svc/console 9090 +``` + +Open your browser to http://localhost:9090 and use the JWT token to log in +to the Operator Console. + + + +Click **+ Create Tenant** to open the Tenant Creation workflow. + +### 3) Build the Tenant Configuration + +The Operator Console **Create New Tenant** walkthrough builds out +a MinIO Tenant. The following list describes the basic configuration sections. + +- **Name** - Specify the *Name*, *Namespace*, and *Storage Class* for the new Tenant. + + The *Storage Class* must correspond to a [Storage Class](#default-storage-class) that corresponds to [Local Persistent Volumes](#local-persistent-volumes) that can support the MinIO Tenant. + + The *Namespace* must correspond to an existing [Namespace](#minio-tenant-namespace) that does *not* contain any other MinIO Tenant. + + Enable *Advanced Mode* to access additional advanced configuration options. + +- **Tenant Size** - Specify the *Number of Servers*, *Number of Drives per Server*, and *Total Size* of the Tenant. + + The *Resource Allocation* section summarizes the Tenant configuration + based on the inputs above. + + Additional configuration inputs may be visible if *Advanced Mode* was enabled + in the previous step. + +- **Preview Configuration** - summarizes the details of the new Tenant. + +After configuring the Tenant to your requirements, click **Create** to create the new tenant. + +The Operator Console displays credentials for connecting to the MinIO Tenant. You *must* download and secure these credentials at this stage. You cannot trivially retrieve these credentials later. + +You can monitor Tenant creation from the Operator Console. \ No newline at end of file diff --git a/charts/minio/minio-operator/6.0.1/templates/_helpers.tpl b/charts/minio/minio-operator/6.0.1/templates/_helpers.tpl new file mode 100644 index 000000000..9c41dd569 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/_helpers.tpl @@ -0,0 +1,59 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "minio-operator.name" -}} + {{- default .Chart.Name | 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 "minio-operator.fullname" -}} + {{- $name := default .Chart.Name -}} + {{- if contains $name .Release.Name -}} + {{- .Release.Name | trunc 63 | trimSuffix "-" -}} + {{- else -}} + {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} + {{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified console 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 "minio-operator.console-fullname" -}} + {{- printf "%s-%s" .Release.Name "console" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "minio-operator.chart" -}} + {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels for operator +*/}} +{{- define "minio-operator.labels" -}} +helm.sh/chart: {{ include "minio-operator.chart" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- range $key, $val := .Values.operator.additionalLabels }} +{{ $key }}: {{ $val | quote }} +{{- end }} +{{- end -}} + +{{/* +Selector labels Operator +*/}} +{{- define "minio-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "minio-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} diff --git a/charts/minio/minio-operator/6.0.1/templates/job.min.io_jobs.yaml b/charts/minio/minio-operator/6.0.1/templates/job.min.io_jobs.yaml new file mode 100644 index 000000000..044c0d6e3 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/job.min.io_jobs.yaml @@ -0,0 +1,1201 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + operator.min.io/version: v6.0.1 + name: miniojobs.job.min.io +spec: + group: job.min.io + names: + kind: MinIOJob + listKind: MinIOJobList + plural: miniojobs + shortNames: + - miniojob + singular: miniojob + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.tenant.name + name: Tenant + type: string + - jsonPath: .spec.status.phase + name: Phase + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + commands: + items: + properties: + args: + additionalProperties: + type: string + type: object + command: + items: + type: string + type: array + dependsOn: + items: + type: string + type: array + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + name: + type: string + op: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + type: array + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + execution: + default: parallel + enum: + - parallel + - sequential + type: string + failureStrategy: + default: continueOnFailure + enum: + - continueOnFailure + - stopOnFailure + type: string + imagePullPolicy: + type: string + imagePullSecret: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + mcImage: + default: quay.io/minio/mc:RELEASE.2024-07-16T23-46-41Z + type: string + securityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccountName: + type: string + tenant: + properties: + name: + type: string + namespace: + type: string + required: + - name + - namespace + type: object + required: + - commands + - serviceAccountName + - tenant + type: object + status: + properties: + commands: + items: + properties: + message: + type: string + name: + type: string + result: + type: string + required: + - result + type: object + type: array + message: + type: string + phase: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/minio/minio-operator/6.0.1/templates/minio.min.io_tenants.yaml b/charts/minio/minio-operator/6.0.1/templates/minio.min.io_tenants.yaml new file mode 100644 index 000000000..547a893ff --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/minio.min.io_tenants.yaml @@ -0,0 +1,5670 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + operator.min.io/version: v6.0.1 + name: tenants.minio.min.io +spec: + group: minio.min.io + names: + kind: Tenant + listKind: TenantList + plural: tenants + shortNames: + - tenant + singular: tenant + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.currentState + name: State + type: string + - jsonPath: .status.healthStatus + name: Health + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v2 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + scheduler: + properties: + name: + type: string + required: + - name + type: object + spec: + properties: + additionalVolumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + additionalVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + buckets: + items: + properties: + name: + type: string + objectLock: + type: boolean + region: + type: string + type: object + type: array + certConfig: + properties: + commonName: + type: string + dnsNames: + items: + type: string + type: array + organizationName: + items: + type: string + type: array + type: object + configuration: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + exposeServices: + properties: + console: + type: boolean + minio: + type: boolean + type: object + externalCaCertSecret: + items: + properties: + name: + type: string + type: + type: string + required: + - name + type: object + type: array + externalCertSecret: + items: + properties: + name: + type: string + type: + type: string + required: + - name + type: object + type: array + externalClientCertSecret: + properties: + name: + type: string + type: + type: string + required: + - name + type: object + externalClientCertSecrets: + items: + properties: + name: + type: string + type: + type: string + required: + - name + type: object + type: array + features: + properties: + bucketDNS: + type: boolean + domains: + properties: + console: + type: string + minio: + items: + type: string + type: array + type: object + enableSFTP: + type: boolean + type: object + image: + type: string + imagePullPolicy: + type: string + imagePullSecret: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + initContainers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + kes: + properties: + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + annotations: + additionalProperties: + type: string + type: object + clientCertSecret: + properties: + name: + type: string + type: + type: string + required: + - name + type: object + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + externalCertSecret: + properties: + name: + type: string + type: + type: string + required: + - name + type: object + gcpCredentialSecretName: + type: string + gcpWorkloadIdentityPool: + type: string + image: + type: string + imagePullPolicy: + type: string + kesSecret: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + keyName: + type: string + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + replicas: + format: int32 + type: integer + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + securityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccountName: + type: string + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + required: + - kesSecret + type: object + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + liveness: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + logging: + properties: + anonymous: + type: boolean + json: + type: boolean + quiet: + type: boolean + type: object + mountPath: + type: string + podManagementPolicy: + type: string + pools: + items: + properties: + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + annotations: + additionalProperties: + type: string + type: object + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + labels: + additionalProperties: + type: string + type: object + name: + minLength: 1 + type: string + nodeSelector: + additionalProperties: + type: string + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + securityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + servers: + format: int32 + type: integer + x-kubernetes-validations: + - message: servers is immutable + rule: self == oldSelf + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeClaimTemplate: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + volumesPerServer: + format: int32 + type: integer + x-kubernetes-validations: + - message: volumesPerServer is immutable + rule: self == oldSelf + required: + - name + - servers + - volumeClaimTemplate + - volumesPerServer + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + priorityClassName: + type: string + prometheusOperator: + type: boolean + readiness: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + requestAutoCert: + type: boolean + serviceAccountName: + type: string + serviceMetadata: + properties: + consoleServiceAnnotations: + additionalProperties: + type: string + type: object + consoleServiceLabels: + additionalProperties: + type: string + type: object + minioServiceAnnotations: + additionalProperties: + type: string + type: object + minioServiceLabels: + additionalProperties: + type: string + type: object + type: object + sideCars: + properties: + containers: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + default: "" + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + volumeClaimTemplates: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + volumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + default: "" + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object + startup: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + subPath: + type: string + users: + items: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + type: array + required: + - pools + type: object + status: + properties: + availableReplicas: + format: int32 + type: integer + certificates: + nullable: true + properties: + autoCertEnabled: + nullable: true + type: boolean + customCertificates: + nullable: true + properties: + client: + items: + properties: + certName: + type: string + domains: + items: + type: string + type: array + expiresIn: + type: string + expiry: + type: string + serialNo: + type: string + type: object + type: array + minio: + items: + properties: + certName: + type: string + domains: + items: + type: string + type: array + expiresIn: + type: string + expiry: + type: string + serialNo: + type: string + type: object + type: array + minioCAs: + items: + properties: + certName: + type: string + domains: + items: + type: string + type: array + expiresIn: + type: string + expiry: + type: string + serialNo: + type: string + type: object + type: array + type: object + type: object + currentState: + type: string + drivesHealing: + format: int32 + type: integer + drivesOffline: + format: int32 + type: integer + drivesOnline: + format: int32 + type: integer + healthMessage: + type: string + healthStatus: + type: string + pools: + items: + properties: + legacySecurityContext: + type: boolean + ssName: + type: string + state: + type: string + required: + - ssName + - state + type: object + nullable: true + type: array + provisionedBuckets: + type: boolean + provisionedUsers: + type: boolean + revision: + format: int32 + type: integer + syncVersion: + type: string + usage: + properties: + capacity: + format: int64 + type: integer + rawCapacity: + format: int64 + type: integer + rawUsage: + format: int64 + type: integer + tiers: + items: + properties: + Name: + type: string + Type: + type: string + totalSize: + format: int64 + type: integer + required: + - Name + - totalSize + type: object + type: array + usage: + format: int64 + type: integer + type: object + waitingOnReady: + format: date-time + type: string + writeQuorum: + format: int32 + type: integer + required: + - availableReplicas + - certificates + - currentState + - pools + - revision + - syncVersion + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/minio/minio-operator/6.0.1/templates/operator-clusterrole.yaml b/charts/minio/minio-operator/6.0.1/templates/operator-clusterrole.yaml new file mode 100644 index 000000000..47cbc265d --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/operator-clusterrole.yaml @@ -0,0 +1,180 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: minio-operator-role + labels: {{- include "minio-operator.labels" . | nindent 4 }} +rules: + - apiGroups: + - "apiextensions.k8s.io" + resources: + - customresourcedefinitions + verbs: + - get + - update + - apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - get + - update + - list + - apiGroups: + - "" + resources: + - namespaces + - nodes + verbs: + - create + - get + - watch + - list + - apiGroups: + - "" + resources: + - pods + - services + - events + - configmaps + verbs: + - get + - watch + - create + - list + - delete + - deletecollection + - update + - patch + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - watch + - create + - update + - list + - delete + - deletecollection + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + - rolebindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apps + resources: + - statefulsets + - deployments + - deployments/finalizers + verbs: + - get + - create + - list + - patch + - watch + - update + - delete + - apiGroups: + - batch + resources: + - jobs + verbs: + - get + - create + - list + - patch + - watch + - update + - delete + - apiGroups: + - "certificates.k8s.io" + resources: + - "certificatesigningrequests" + - "certificatesigningrequests/approval" + - "certificatesigningrequests/status" + verbs: + - update + - create + - get + - delete + - list + - apiGroups: + - certificates.k8s.io + resourceNames: + - kubernetes.io/legacy-unknown + - kubernetes.io/kube-apiserver-client + - kubernetes.io/kubelet-serving + - beta.eks.amazonaws.com/app-serving + resources: + - signers + verbs: + - approve + - sign + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - minio.min.io + - sts.min.io + - job.min.io + resources: + - "*" + verbs: + - "*" + - apiGroups: + - min.io + resources: + - "*" + verbs: + - "*" + - apiGroups: + - monitoring.coreos.com + resources: + - prometheuses + verbs: + - '*' + - apiGroups: + - "coordination.k8s.io" + resources: + - leases + verbs: + - get + - update + - create + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - create + - delete + - get + - list + - patch + - update + - deletecollection diff --git a/charts/minio/minio-operator/6.0.1/templates/operator-clusterrolebinding.yaml b/charts/minio/minio-operator/6.0.1/templates/operator-clusterrolebinding.yaml new file mode 100644 index 000000000..ad4add53d --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/operator-clusterrolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: minio-operator-binding + labels: {{- include "minio-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: minio-operator-role +subjects: + - kind: ServiceAccount + name: minio-operator + namespace: {{ .Release.Namespace }} diff --git a/charts/minio/minio-operator/6.0.1/templates/operator-deployment.yaml b/charts/minio/minio-operator/6.0.1/templates/operator-deployment.yaml new file mode 100644 index 000000000..5ffbd3178 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/operator-deployment.yaml @@ -0,0 +1,67 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: minio-operator + namespace: {{ .Release.Namespace }} + labels: {{- include "minio-operator.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.operator.replicaCount }} + selector: + matchLabels: {{- include "minio-operator.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "minio-operator.labels" . | nindent 8 }} + {{- include "minio-operator.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.operator.imagePullSecrets }} + imagePullSecrets: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.runtimeClassName }} + runtimeClassName: {{ . }} + {{- end }} + serviceAccountName: minio-operator + {{- with .Values.operator.securityContext }} + securityContext: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.affinity }} + affinity: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.tolerations }} + tolerations: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.topologySpreadConstraints }} + topologySpreadConstraints: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.operator.initContainers }} + initContainers: {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.operator.image.repository }}:{{ .Values.operator.image.digest | default .Values.operator.image.tag }}" + imagePullPolicy: {{ .Values.operator.image.pullPolicy }} + args: + - controller + {{- with .Values.operator.env }} + env: {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.operator.sidecarImage }} + - name: "OPERATOR_SIDECAR_IMAGE" + value: "{{ .Values.operator.sidecarImage.repository }}:{{ .Values.operator.sidecarImage.digest | default .Values.operator.sidecarImage.tag }}" + {{- end }} + resources: {{- toYaml .Values.operator.resources | nindent 12 }} + {{- with .Values.operator.containerSecurityContext }} + securityContext: {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.operator.volumeMounts }} + volumeMounts: {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.operator.volumes }} + volumes: {{- toYaml . | nindent 8 }} + {{- end }} \ No newline at end of file diff --git a/charts/minio/minio-operator/6.0.1/templates/operator-service.yaml b/charts/minio/minio-operator/6.0.1/templates/operator-service.yaml new file mode 100644 index 000000000..33f25fbbb --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/operator-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + name: operator + namespace: {{ .Release.Namespace }} + labels: {{- include "minio-operator.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: 4221 + name: http + selector: + operator: leader + {{- include "minio-operator.selectorLabels" . | nindent 4 }} diff --git a/charts/minio/minio-operator/6.0.1/templates/operator-serviceaccount.yaml b/charts/minio/minio-operator/6.0.1/templates/operator-serviceaccount.yaml new file mode 100644 index 000000000..8ae899da6 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/operator-serviceaccount.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: minio-operator + namespace: {{ .Release.Namespace }} + labels: {{- include "minio-operator.labels" . | nindent 4 }} + {{- with .Values.operator.serviceAccountAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} diff --git a/charts/minio/minio-operator/6.0.1/templates/sts-service.yaml b/charts/minio/minio-operator/6.0.1/templates/sts-service.yaml new file mode 100644 index 000000000..51b06a590 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/sts-service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: sts + namespace: {{ .Release.Namespace }} + labels: {{- include "minio-operator.labels" . | nindent 4 }} +spec: + type: ClusterIP + ports: + - port: 4223 + name: https + selector: {{- include "minio-operator.selectorLabels" . | nindent 4 }} diff --git a/charts/minio/minio-operator/6.0.1/templates/sts.min.io_policybindings.yaml b/charts/minio/minio-operator/6.0.1/templates/sts.min.io_policybindings.yaml new file mode 100644 index 000000000..f41e8c7d5 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/templates/sts.min.io_policybindings.yaml @@ -0,0 +1,133 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + operator.min.io/version: v6.0.1 + name: policybindings.sts.min.io +spec: + group: sts.min.io + names: + kind: PolicyBinding + listKind: PolicyBindingList + plural: policybindings + shortNames: + - policybinding + singular: policybinding + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.currentState + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + application: + properties: + namespace: + type: string + serviceaccount: + type: string + required: + - namespace + - serviceaccount + type: object + policies: + items: + type: string + type: array + required: + - application + - policies + type: object + status: + properties: + currentState: + type: string + usage: + nullable: true + properties: + authotizations: + format: int64 + type: integer + type: object + required: + - currentState + - usage + type: object + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.currentState + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1beta1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + application: + properties: + namespace: + type: string + serviceaccount: + type: string + required: + - namespace + - serviceaccount + type: object + policies: + items: + type: string + type: array + required: + - application + - policies + type: object + status: + properties: + currentState: + type: string + usage: + nullable: true + properties: + authotizations: + format: int64 + type: integer + type: object + required: + - currentState + - usage + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/minio/minio-operator/6.0.1/values.yaml b/charts/minio/minio-operator/6.0.1/values.yaml new file mode 100644 index 000000000..19820eee6 --- /dev/null +++ b/charts/minio/minio-operator/6.0.1/values.yaml @@ -0,0 +1,191 @@ +### +# Root key for Operator Helm Chart +operator: + ### + # An array of environment variables to pass to the Operator deployment. + # Pass an empty array to start Operator with defaults. + # + # For example: + # + # .. code-block:: yaml + # + # env: + # - name: MINIO_OPERATOR_DEPLOYMENT_NAME + # valueFrom: + # fieldRef: + # fieldPath: metadata.labels['app.kubernetes.io/name'] + # - name: CLUSTER_DOMAIN + # value: "cluster.domain" + # - name: WATCHED_NAMESPACE + # value: "" + # - name: MINIO_OPERATOR_RUNTIME + # value: "OpenShift" + # + # See `Operator environment variables `__ for a list of all supported values. + env: + - name: OPERATOR_STS_ENABLED + value: "on" + # An array of additional annotations to be applied to the operator service account + serviceAccountAnnotations: [] + # additional labels to be applied to operator resources + additionalLabels: {} + ### + # Specify the Operator container image to use for the deployment. + # ``image.tag`` + # For example, the following sets the image to the ``quay.io/minio/operator`` repo and the v6.0.1 tag. + # The container pulls the image if not already present: + # + # .. code-block:: yaml + # + # image: + # repository: quay.io/minio/operator + # tag: v6.0.1 + # pullPolicy: IfNotPresent + # + # The chart also supports specifying an image based on digest value: + # + # .. code-block:: yaml + # + # image: + # repository: quay.io/minio/operator@sha256 + # digest: 28c80b379c75242c6fe793dfbf212f43c602140a0de5ebe3d9c2a3a7b9f9f983 + # pullPolicy: IfNotPresent + # + image: + repository: quay.io/minio/operator + tag: v6.0.1 + pullPolicy: IfNotPresent + ### + # Specify the sidecar container image to deploy on tenant pods for init container and sidecar. + # Only need to change this if want to use a different version that the default, or want to set a custom registry. + # ``sidecarImage.tag`` + # For example, the following sets the image to the ``quay.io/minio/operator-sidecar`` repo and the v6.0.1 tag. + # The container pulls the image if not already present: + # + # .. code-block:: yaml + # + # sidecarImage: + # repository: quay.io/minio/operator-sidecar + # tag: v6.0.1 + # pullPolicy: IfNotPresent + # + # The chart also supports specifying an image based on digest value: + # + # .. code-block:: yaml + # + # sidecarImage: + # repository: quay.io/minio/operator-sidecar@sha256 + # digest: a11947a230b80fb1b0bffa97173147a505d4f1207958f722e348d11ab9e972c1 + # pullPolicy: IfNotPresent + # + sidecarImage: {} + ### + # + # An array of Kubernetes secrets to use for pulling images from a private ``image.repository``. + # Only one array element is supported at this time. + imagePullSecrets: [ ] + ### + # + # The name of a custom `Container Runtime `__ to use for the Operator pods. + runtimeClassName: ~ + ### + # An array of `initContainers `__ to start up before the Operator pods. + # Exercise care as ``initContainer`` failures prevent Operator pods from starting. + # Pass an empty array to start the Operator normally. + initContainers: [ ] + ### + # The number of Operator pods to deploy. + # Higher values increase availability in the event of worker node failures. + # + # The cluster must have sufficient number of available worker nodes to fulfill the request. + # Operator pods deploy with pod anti-affinity by default, preventing Kubernetes from scheduling multiple pods onto a single Worker node. + replicaCount: 2 + ### + # The Kubernetes `SecurityContext `__ to use for deploying Operator resources. + # + # You may need to modify these values to meet your cluster's security and access settings. + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + runAsNonRoot: true + fsGroup: 1000 + ### + # The Kubernetes `SecurityContext `__ to use for deploying Operator containers. + # You may need to modify these values to meet your cluster's security and access settings. + containerSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + runAsNonRoot: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + ### + # An array of `Volumes `__ which the Operator can mount to pods. + # + # The volumes must exist *and* be accessible to the Operator pods. + volumes: [ ] + ### + # An array of volume mount points associated to each Operator container. + # + # Specify each item in the array as follows: + # + # .. code-block:: yaml + # + # volumeMounts: + # - name: volumename + # mountPath: /path/to/mount + # + # The ``name`` field must correspond to an entry in the ``volumes`` array. + volumeMounts: [ ] + ### + # Any `Node Selectors `__ to apply to Operator pods. + # + # The Kubernetes scheduler uses these selectors to determine which worker nodes onto which it can deploy Operator pods. + # + # If no worker nodes match the specified selectors, the Operator deployment will fail. + nodeSelector: { } + ### + # + # The `Pod Priority `__ to assign to Operator pods. + priorityClassName: "" + ### + # + # The `affinity `__ or anti-affinity settings to apply to Operator pods. + # + # These settings determine the distribution of pods across worker nodes and can help prevent or allow colocating pods onto the same worker nodes. + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: name + operator: In + values: + - minio-operator + topologyKey: kubernetes.io/hostname + ### + # + # An array of `Toleration labels `__ to associate to Operator pods. + # + # These settings determine the distribution of pods across worker nodes. + tolerations: [ ] + ### + # + # An array of `Topology Spread Constraints `__ to associate to Operator pods. + # + # These settings determine the distribution of pods across worker nodes. + topologySpreadConstraints: [ ] + ### + # + # The `Requests or Limits `__ for resources to associate to Operator pods. + # + # These settings can control the minimum and maximum resources requested for each pod. + # If no worker nodes can meet the specified requests, the Operator may fail to deploy. + resources: + requests: + cpu: 200m + memory: 256Mi + ephemeral-storage: 500Mi diff --git a/charts/new-relic/nri-bundle/5.0.87/.helmignore b/charts/new-relic/nri-bundle/5.0.87/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/Chart.lock new file mode 100644 index 000000000..2fe31407d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/Chart.lock @@ -0,0 +1,39 @@ +dependencies: +- name: newrelic-infrastructure + repository: https://newrelic.github.io/nri-kubernetes + version: 3.34.2 +- name: nri-prometheus + repository: https://newrelic.github.io/nri-prometheus + version: 2.1.18 +- name: newrelic-prometheus-agent + repository: https://newrelic.github.io/newrelic-prometheus-configurator + version: 1.14.2 +- name: nri-metadata-injection + repository: https://newrelic.github.io/k8s-metadata-injection + version: 4.20.2 +- name: newrelic-k8s-metrics-adapter + repository: https://newrelic.github.io/newrelic-k8s-metrics-adapter + version: 1.11.0 +- name: kube-state-metrics + repository: https://prometheus-community.github.io/helm-charts + version: 5.12.1 +- name: nri-kube-events + repository: https://newrelic.github.io/nri-kube-events + version: 3.10.1 +- name: newrelic-logging + repository: https://newrelic.github.io/helm-charts + version: 1.22.3 +- name: newrelic-pixie + repository: https://newrelic.github.io/helm-charts + version: 2.1.4 +- name: k8s-agents-operator + repository: https://newrelic.github.io/k8s-agents-operator + version: 0.10.0 +- name: pixie-operator-chart + repository: https://pixie-operator-charts.storage.googleapis.com + version: 0.1.6 +- name: newrelic-infra-operator + repository: https://newrelic.github.io/newrelic-infra-operator + version: 2.11.0 +digest: sha256:ae41b9b8cf9ce69f95bb32399ec9abf2e60808db2b54a199a8f3945f5f1d6da1 +generated: "2024-07-22T16:39:33.230811215Z" diff --git a/charts/new-relic/nri-bundle/5.0.87/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/Chart.yaml new file mode 100644 index 000000000..b9d5bbe43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/Chart.yaml @@ -0,0 +1,85 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: New Relic + catalog.cattle.io/release-name: nri-bundle +apiVersion: v2 +dependencies: +- condition: infrastructure.enabled,newrelic-infrastructure.enabled + name: newrelic-infrastructure + repository: file://./charts/newrelic-infrastructure + version: 3.34.2 +- condition: prometheus.enabled,nri-prometheus.enabled + name: nri-prometheus + repository: file://./charts/nri-prometheus + version: 2.1.18 +- condition: newrelic-prometheus-agent.enabled + name: newrelic-prometheus-agent + repository: file://./charts/newrelic-prometheus-agent + version: 1.14.2 +- condition: webhook.enabled,nri-metadata-injection.enabled + name: nri-metadata-injection + repository: file://./charts/nri-metadata-injection + version: 4.20.2 +- condition: metrics-adapter.enabled,newrelic-k8s-metrics-adapter.enabled + name: newrelic-k8s-metrics-adapter + repository: file://./charts/newrelic-k8s-metrics-adapter + version: 1.11.0 +- condition: ksm.enabled,kube-state-metrics.enabled + name: kube-state-metrics + repository: file://./charts/kube-state-metrics + version: 5.12.1 +- condition: kubeEvents.enabled,nri-kube-events.enabled + name: nri-kube-events + repository: file://./charts/nri-kube-events + version: 3.10.1 +- condition: logging.enabled,newrelic-logging.enabled + name: newrelic-logging + repository: file://./charts/newrelic-logging + version: 1.22.3 +- condition: newrelic-pixie.enabled + name: newrelic-pixie + repository: file://./charts/newrelic-pixie + version: 2.1.4 +- condition: k8s-agents-operator.enabled + name: k8s-agents-operator + repository: file://./charts/k8s-agents-operator + version: 0.10.0 +- alias: pixie-chart + condition: pixie-chart.enabled + name: pixie-operator-chart + repository: file://./charts/pixie-operator-chart + version: 0.1.6 +- condition: newrelic-infra-operator.enabled + name: newrelic-infra-operator + repository: file://./charts/newrelic-infra-operator + version: 2.11.0 +description: Groups together the individual charts for the New Relic Kubernetes solution + for a more comfortable deployment. +home: https://github.com/newrelic/helm-charts +icon: file://assets/icons/nri-bundle.svg +keywords: +- infrastructure +- newrelic +- monitoring +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +name: nri-bundle +sources: +- https://github.com/newrelic/nri-bundle/ +- https://github.com/newrelic/nri-bundle/tree/master/charts/nri-bundle +- https://github.com/newrelic/nri-kubernetes/tree/master/charts/newrelic-infrastructure +- https://github.com/newrelic/nri-prometheus/tree/master/charts/nri-prometheus +- https://github.com/newrelic/newrelic-prometheus-configurator/tree/master/charts/newrelic-prometheus-agent +- https://github.com/newrelic/k8s-metadata-injection/tree/master/charts/nri-metadata-injection +- https://github.com/newrelic/newrelic-k8s-metrics-adapter/tree/master/charts/newrelic-k8s-metrics-adapter +- https://github.com/newrelic/nri-kube-events/tree/master/charts/nri-kube-events +- https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging +- https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-pixie +- https://github.com/newrelic/newrelic-infra-operator/tree/master/charts/newrelic-infra-operator +- https://github.com/newrelic/k8s-agents-operator/tree/master/charts/k8s-agents-operator +version: 5.0.87 diff --git a/charts/new-relic/nri-bundle/5.0.87/README.md b/charts/new-relic/nri-bundle/5.0.87/README.md new file mode 100644 index 000000000..3fcc97d2b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/README.md @@ -0,0 +1,200 @@ +# nri-bundle + +Groups together the individual charts for the New Relic Kubernetes solution for a more comfortable deployment. + +**Homepage:** + +## Bundled charts + +This chart does not deploy anything by itself but has many charts as dependencies. This allows you to easily install and upgrade the New Relic +Kubernetes Integration using only one chart. + +In case you need more information about each component this chart installs, or you are an advanced user that want to install each component separately, +here is a list of components that this chart installs and where you can find more information about them: + +| Component | Installed by default? | Description | +|------------------------------|-----------------------|-------------| +| [newrelic-infrastructure](https://github.com/newrelic/nri-kubernetes/tree/main/charts/newrelic-infrastructure) | Yes | Sends metrics about nodes, cluster objects (e.g. Deployments, Pods), and the control plane to New Relic. | +| [nri-metadata-injection](https://github.com/newrelic/k8s-metadata-injection/tree/main/charts/nri-metadata-injection) | Yes | Enriches New Relic-instrumented applications (APM) with Kubernetes information. | +| [kube-state-metrics](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics) | | Required for `newrelic-infrastructure` to gather cluster-level metrics. | +| [nri-kube-events](https://github.com/newrelic/nri-kube-events/tree/main/charts/nri-kube-events) | | Reports Kubernetes events to New Relic. | +| [newrelic-infra-operator](https://github.com/newrelic/newrelic-infra-operator/tree/main/charts/newrelic-infra-operator) | | (Beta) Used with Fargate or serverless environments to inject `newrelic-infrastructure` as a sidecar instead of the usual DaemonSet. | +| [newrelic-k8s-metrics-adapter](https://github.com/newrelic/newrelic-k8s-metrics-adapter/tree/main/charts/newrelic-k8s-metrics-adapter) | | (Beta) Provides a source of data for Horizontal Pod Autoscalers (HPA) based on a NRQL query from New Relic. | +| [newrelic-logging](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging) | | Sends logs for Kubernetes components and workloads running on the cluster to New Relic. | +| [nri-prometheus](https://github.com/newrelic/nri-prometheus/tree/main/charts/nri-prometheus) | | Sends metrics from applications exposing Prometheus metrics to New Relic. | +| [newrelic-prometheus-configurator](https://github.com/newrelic/newrelic-prometheus-configurator/tree/master/charts/newrelic-prometheus-agent) | | Configures instances of Prometheus in Agent mode to send metrics to the New Relic Prometheus endpoint. | +| [newrelic-pixie](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-pixie) | | Connects to the Pixie API and enables the New Relic plugin in Pixie. The plugin allows you to export data from Pixie to New Relic for long-term data retention. | +| [Pixie](https://docs.pixielabs.ai/installing-pixie/install-schemes/helm/#3.-deploy) | | Is an open source observability tool for Kubernetes applications that uses eBPF to automatically capture telemetry data without the need for manual instrumentation. | +| [k8s-agents-operator](https://github.com/newrelic/k8s-agents-operator/tree/main/charts/k8s-agents-operator) | | (Preview) Streamlines full-stack observability for Kubernetes environments by automating APM instrumentation alongside Kubernetes agent deployment. | + +## Configure components + +It is possible to configure settings for the individual charts this chart groups by specifying values for them under a key using the name of the chart, +as specified in [helm documentation](https://helm.sh/docs/chart_template_guide/subcharts_and_globals). + +For example, by adding the following to the `values.yml` file: + +```yaml +# Configuration settings for the newrelic-infrastructure chart +newrelic-infrastructure: + # Any key defined in the values.yml file for the newrelic-infrastructure chart can be configured here: + # https://github.com/newrelic/nri-kubernetes/blob/main/charts/newrelic-infrastructure/values.yaml + + verboseLog: false + + resources: + limits: + memory: 512M +``` + +It is possible to override any entry of the [`newrelic-infrastructure`](https://github.com/newrelic/nri-kubernetes/tree/main/charts/newrelic-infrastructure) +chart, as defined in their [`values.yml` file](https://github.com/newrelic/nri-kubernetes/blob/main/charts/newrelic-infrastructure/values.yaml). + +The same approach can be followed to update any of the subcharts. + +After making these changes to the `values.yml` file, or a custom values file, make sure to apply them using: + +``` +$ helm upgrade --reuse-values -f values.yaml [RELEASE] newrelic/nri-bundle +``` + +Where `[RELEASE]` is the name of the helm release, e.g. `newrelic-bundle`. + +## Monitor on host integrations + +If you wish to monitor services running on Kubernetes you can provide integrations +configuration under `integrations_config` that it will passed down to the `newrelic-infrastructure` chart. + +You just need to create a new entry where the "name" is the filename of the configuration file and the data is the content of +the integration configuration. The name must end in ".yaml" as this will be the +filename generated and the Infrastructure agent only looks for YAML files. + +The data part is the actual integration configuration as described in the spec here: +https://docs.newrelic.com/docs/integrations/integrations-sdk/file-specifications/integration-configuration-file-specifications-agent-v180 + +In the following example you can see how to monitor a Redis integration with autodiscovery + +```yaml +newrelic-infrastructure: + integrations: + nri-redis-sampleapp: + discovery: + command: + exec: /var/db/newrelic-infra/nri-discovery-kubernetes --tls --port 10250 + match: + label.app: sampleapp + integrations: + - name: nri-redis + env: + # using the discovered IP as the hostname address + HOSTNAME: ${discovery.ip} + PORT: 6379 + labels: + env: test +``` + +## Bring your own KSM + +New Relic Kubernetes Integration requires an instance of kube-state-metrics (KSM) to be running in the cluster, which this chart pulls as a dependency. If you are already running or want to run your own KSM instance, you will need to make some small adjustments as described below. + +### Bring your own KSM + +If you already have one KSM instance running, you can point `nri-kubernetes` to your instance: + +```yaml +kube-state-metrics: + # Disable bundled KSM. + enabled: false +newrelic-infrastructure: + ksm: + config: + # Selector for your pre-installed KSM Service. You may need to adjust this to fit your existing installation. + selector: "app.kubernetes.io/name=kube-state-metrics" + # Alternatively, you can specify a fixed URL where KSM is available. Doing so will bypass autodiscovery. + #staticUrl: http://ksm.ksm.svc.cluster.local:8080/metrics +``` + +### Run KSM alongside a different version + +If you need to run a different instance of KSM in your cluster, you can still run a separate instance for the Kubernetes Integration to work as intended: + +```yaml +kube-state-metrics: + # Enable bundled KSM. + enabled: true + prometheusScrape: false + customLabels: + # Label unique to this KSM instance. + newrelic.com/custom-ksm: "true" +newrelic-infrastructure: + ksm: + config: + # Use label above as a selector. + selector: "newrelic.com/custom-ksm=true" +``` + +For more information on supported KSM version visit the [requirements documentation](https://docs.newrelic.com/docs/kubernetes-pixie/kubernetes-integration/get-started/kubernetes-integration-compatibility-requirements#reqs) + +## Values managed globally + +Some of the subchart implement the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +At the time of writing this document, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this library and +honors global options as described below. + +Note, the value table below is automatically generated from `values.yaml` by `helm-docs`. If you need to add new fields or update existing fields, please update the `values.yaml` and then run `helm-docs` to update this value table. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| global | object | See [`values.yaml`](values.yaml) | change the behaviour globally to all the supported helm charts. See [user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md) for further information. | +| global.affinity | object | `{}` | Sets pod/node affinities | +| global.cluster | string | `""` | The cluster name for the Kubernetes cluster. | +| global.containerSecurityContext | object | `{}` | Sets security context (at container level) | +| global.customAttributes | object | `{}` | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.customSecretLicenseKey | string | `""` | Key in the Secret object where the license key is stored | +| global.customSecretName | string | `""` | Name of the Secret object where the license key is stored | +| global.dnsConfig | object | `{}` | Sets pod's dnsConfig | +| global.fargate | bool | false | Must be set to `true` when deploying in an EKS Fargate environment | +| global.hostNetwork | bool | false | Sets pod's hostNetwork | +| global.images.pullSecrets | list | `[]` | Set secrets to be able to fetch images | +| global.images.registry | string | `""` | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.insightsKey | string | `""` | The license key for your New Relic Account. This will be preferred configuration option if both `insightsKey` and `customSecret` are specified. | +| global.labels | object | `{}` | Additional labels for chart objects | +| global.licenseKey | string | `""` | The license key for your New Relic Account. This will be preferred configuration option if both `licenseKey` and `customSecret` are specified. | +| global.lowDataMode | bool | false | Reduces number of metrics sent in order to reduce costs | +| global.nodeSelector | object | `{}` | Sets pod's node selector | +| global.nrStaging | bool | false | Send the metrics to the staging backend. Requires a valid staging license key | +| global.podLabels | object | `{}` | Additional labels for chart pods | +| global.podSecurityContext | object | `{}` | Sets security context (at pod level) | +| global.priorityClassName | string | `""` | Sets pod's priorityClassName | +| global.privileged | bool | false | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | | +| global.proxy | string | `""` | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.serviceAccount.annotations | object | `{}` | Add these annotations to the service account we create | +| global.serviceAccount.create | string | `nil` | Configures if the service account should be created or not | +| global.serviceAccount.name | string | `nil` | Change the name of the service account. This is honored if you disable on this chart the creation of the service account so you can use your own | +| global.tolerations | list | `[]` | Sets pod's tolerations to node taints | +| global.verboseLog | bool | false | Sets the debug logs to this integration or all integrations if it is set globally | +| k8s-agents-operator.enabled | bool | `false` | Install the [`k8s-agents-operator` chart](https://github.com/newrelic/k8s-agents-operator/tree/main/charts/k8s-agents-operator) | +| kube-state-metrics.enabled | bool | `false` | Install the [`kube-state-metrics` chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics) from the stable helm charts repository. This is mandatory if `infrastructure.enabled` is set to `true` and the user does not provide its own instance of KSM version >=1.8 and <=2.0. Note, kube-state-metrics v2+ disables labels/annotations metrics by default. You can enable the target labels/annotations metrics to be monitored by using the metricLabelsAllowlist/metricAnnotationsAllowList options described [here](https://github.com/prometheus-community/helm-charts/blob/159cd8e4fb89b8b107dcc100287504bb91bf30e0/charts/kube-state-metrics/values.yaml#L274) in your Kubernetes clusters. | +| newrelic-infra-operator.enabled | bool | `false` | Install the [`newrelic-infra-operator` chart](https://github.com/newrelic/newrelic-infra-operator/tree/main/charts/newrelic-infra-operator) (Beta) | +| newrelic-infrastructure.enabled | bool | `true` | Install the [`newrelic-infrastructure` chart](https://github.com/newrelic/nri-kubernetes/tree/main/charts/newrelic-infrastructure) | +| newrelic-k8s-metrics-adapter.enabled | bool | `false` | Install the [`newrelic-k8s-metrics-adapter.` chart](https://github.com/newrelic/newrelic-k8s-metrics-adapter/tree/main/charts/newrelic-k8s-metrics-adapter) (Beta) | +| newrelic-logging.enabled | bool | `false` | Install the [`newrelic-logging` chart](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging) | +| newrelic-pixie.enabled | bool | `false` | Install the [`newrelic-pixie`](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-pixie) | +| newrelic-prometheus-agent.enabled | bool | `false` | Install the [`newrelic-prometheus-agent` chart](https://github.com/newrelic/newrelic-prometheus-configurator/tree/main/charts/newrelic-prometheus-agent) | +| nri-kube-events.enabled | bool | `false` | Install the [`nri-kube-events` chart](https://github.com/newrelic/nri-kube-events/tree/main/charts/nri-kube-events) | +| nri-metadata-injection.enabled | bool | `true` | Install the [`nri-metadata-injection` chart](https://github.com/newrelic/k8s-metadata-injection/tree/main/charts/nri-metadata-injection) | +| nri-prometheus.enabled | bool | `false` | Install the [`nri-prometheus` chart](https://github.com/newrelic/nri-prometheus/tree/main/charts/nri-prometheus) | +| pixie-chart.enabled | bool | `false` | Install the [`pixie-chart` chart](https://docs.pixielabs.ai/installing-pixie/install-schemes/helm/#3.-deploy) | + +## Maintainers + +* [juanjjaramillo](https://github.com/juanjjaramillo) +* [csongnr](https://github.com/csongnr) +* [dbudziwojskiNR](https://github.com/dbudziwojskiNR) diff --git a/charts/new-relic/nri-bundle/5.0.87/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/README.md.gotmpl new file mode 100644 index 000000000..269c4925a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/README.md.gotmpl @@ -0,0 +1,166 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +## Bundled charts + +This chart does not deploy anything by itself but has many charts as dependencies. This allows you to easily install and upgrade the New Relic +Kubernetes Integration using only one chart. + +In case you need more information about each component this chart installs, or you are an advanced user that want to install each component separately, +here is a list of components that this chart installs and where you can find more information about them: + +| Component | Installed by default? | Description | +|------------------------------|-----------------------|-------------| +| [newrelic-infrastructure](https://github.com/newrelic/nri-kubernetes/tree/main/charts/newrelic-infrastructure) | Yes | Sends metrics about nodes, cluster objects (e.g. Deployments, Pods), and the control plane to New Relic. | +| [nri-metadata-injection](https://github.com/newrelic/k8s-metadata-injection/tree/main/charts/nri-metadata-injection) | Yes | Enriches New Relic-instrumented applications (APM) with Kubernetes information. | +| [kube-state-metrics](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics) | | Required for `newrelic-infrastructure` to gather cluster-level metrics. | +| [nri-kube-events](https://github.com/newrelic/nri-kube-events/tree/main/charts/nri-kube-events) | | Reports Kubernetes events to New Relic. | +| [newrelic-infra-operator](https://github.com/newrelic/newrelic-infra-operator/tree/main/charts/newrelic-infra-operator) | | (Beta) Used with Fargate or serverless environments to inject `newrelic-infrastructure` as a sidecar instead of the usual DaemonSet. | +| [newrelic-k8s-metrics-adapter](https://github.com/newrelic/newrelic-k8s-metrics-adapter/tree/main/charts/newrelic-k8s-metrics-adapter) | | (Beta) Provides a source of data for Horizontal Pod Autoscalers (HPA) based on a NRQL query from New Relic. | +| [newrelic-logging](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging) | | Sends logs for Kubernetes components and workloads running on the cluster to New Relic. | +| [nri-prometheus](https://github.com/newrelic/nri-prometheus/tree/main/charts/nri-prometheus) | | Sends metrics from applications exposing Prometheus metrics to New Relic. | +| [newrelic-prometheus-configurator](https://github.com/newrelic/newrelic-prometheus-configurator/tree/master/charts/newrelic-prometheus-agent) | | Configures instances of Prometheus in Agent mode to send metrics to the New Relic Prometheus endpoint. | +| [newrelic-pixie](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-pixie) | | Connects to the Pixie API and enables the New Relic plugin in Pixie. The plugin allows you to export data from Pixie to New Relic for long-term data retention. | +| [Pixie](https://docs.pixielabs.ai/installing-pixie/install-schemes/helm/#3.-deploy) | | Is an open source observability tool for Kubernetes applications that uses eBPF to automatically capture telemetry data without the need for manual instrumentation. | +| [k8s-agents-operator](https://github.com/newrelic/k8s-agents-operator/tree/main/charts/k8s-agents-operator) | | (Preview) Streamlines full-stack observability for Kubernetes environments by automating APM instrumentation alongside Kubernetes agent deployment. | + +## Configure components + +It is possible to configure settings for the individual charts this chart groups by specifying values for them under a key using the name of the chart, +as specified in [helm documentation](https://helm.sh/docs/chart_template_guide/subcharts_and_globals). + +For example, by adding the following to the `values.yml` file: + +```yaml +# Configuration settings for the newrelic-infrastructure chart +newrelic-infrastructure: + # Any key defined in the values.yml file for the newrelic-infrastructure chart can be configured here: + # https://github.com/newrelic/nri-kubernetes/blob/main/charts/newrelic-infrastructure/values.yaml + + verboseLog: false + + resources: + limits: + memory: 512M +``` + +It is possible to override any entry of the [`newrelic-infrastructure`](https://github.com/newrelic/nri-kubernetes/tree/main/charts/newrelic-infrastructure) +chart, as defined in their [`values.yml` file](https://github.com/newrelic/nri-kubernetes/blob/main/charts/newrelic-infrastructure/values.yaml). + +The same approach can be followed to update any of the subcharts. + +After making these changes to the `values.yml` file, or a custom values file, make sure to apply them using: + +``` +$ helm upgrade --reuse-values -f values.yaml [RELEASE] newrelic/nri-bundle +``` + +Where `[RELEASE]` is the name of the helm release, e.g. `newrelic-bundle`. + + +## Monitor on host integrations + +If you wish to monitor services running on Kubernetes you can provide integrations +configuration under `integrations_config` that it will passed down to the `newrelic-infrastructure` chart. + +You just need to create a new entry where the "name" is the filename of the configuration file and the data is the content of +the integration configuration. The name must end in ".yaml" as this will be the +filename generated and the Infrastructure agent only looks for YAML files. + +The data part is the actual integration configuration as described in the spec here: +https://docs.newrelic.com/docs/integrations/integrations-sdk/file-specifications/integration-configuration-file-specifications-agent-v180 + +In the following example you can see how to monitor a Redis integration with autodiscovery + +```yaml +newrelic-infrastructure: + integrations: + nri-redis-sampleapp: + discovery: + command: + exec: /var/db/newrelic-infra/nri-discovery-kubernetes --tls --port 10250 + match: + label.app: sampleapp + integrations: + - name: nri-redis + env: + # using the discovered IP as the hostname address + HOSTNAME: ${discovery.ip} + PORT: 6379 + labels: + env: test +``` + +## Bring your own KSM + +New Relic Kubernetes Integration requires an instance of kube-state-metrics (KSM) to be running in the cluster, which this chart pulls as a dependency. If you are already running or want to run your own KSM instance, you will need to make some small adjustments as described below. + +### Bring your own KSM + +If you already have one KSM instance running, you can point `nri-kubernetes` to your instance: + +```yaml +kube-state-metrics: + # Disable bundled KSM. + enabled: false +newrelic-infrastructure: + ksm: + config: + # Selector for your pre-installed KSM Service. You may need to adjust this to fit your existing installation. + selector: "app.kubernetes.io/name=kube-state-metrics" + # Alternatively, you can specify a fixed URL where KSM is available. Doing so will bypass autodiscovery. + #staticUrl: http://ksm.ksm.svc.cluster.local:8080/metrics +``` + +### Run KSM alongside a different version + +If you need to run a different instance of KSM in your cluster, you can still run a separate instance for the Kubernetes Integration to work as intended: + +```yaml +kube-state-metrics: + # Enable bundled KSM. + enabled: true + prometheusScrape: false + customLabels: + # Label unique to this KSM instance. + newrelic.com/custom-ksm: "true" +newrelic-infrastructure: + ksm: + config: + # Use label above as a selector. + selector: "newrelic.com/custom-ksm=true" +``` + +For more information on supported KSM version visit the [requirements documentation](https://docs.newrelic.com/docs/kubernetes-pixie/kubernetes-integration/get-started/kubernetes-integration-compatibility-requirements#reqs) + +## Values managed globally + +Some of the subchart implement the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +At the time of writing this document, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this library and +honors global options as described below. + +Note, the value table below is automatically generated from `values.yaml` by `helm-docs`. If you need to add new fields or update existing fields, please update the `values.yaml` and then run `helm-docs` to update this value table. + +{{ template "chart.valuesSection" . }} + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/app-readme.md b/charts/new-relic/nri-bundle/5.0.87/app-readme.md new file mode 100644 index 000000000..61e550787 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/app-readme.md @@ -0,0 +1,5 @@ +# New Relic Kubernetes Integration + +New Relic's Kubernetes integration gives you full observability into the health and performance of your environment, no matter whether you run Kubernetes on-premises or in the cloud. With our [cluster explorer](https://docs.newrelic.com/docs/integrations/kubernetes-integration/cluster-explorer/kubernetes-cluster-explorer), you can cut through layers of complexity to see how your cluster is performing, from the heights of the control plane down to applications running on a single pod. + +You can see the power of the Kubernetes integration in the [cluster explorer](https://docs.newrelic.com/docs/integrations/kubernetes-integration/cluster-explorer/kubernetes-cluster-explorer), where the full picture of a cluster is made available on a single screen: nodes and pods are visualized according to their health and performance, with pending and alerting nodes in the innermost circles. [Predefined alert conditions](https://docs.newrelic.com/docs/integrations/kubernetes-integration/kubernetes-events/kubernetes-integration-predefined-alert-policy) help you troubleshoot issues right from the start. Clicking each node reveals its status and how each app is performing. \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/Chart.yaml new file mode 100644 index 000000000..44a9c5d85 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/Chart.yaml @@ -0,0 +1,16 @@ +apiVersion: v2 +appVersion: 0.10.0 +description: A Helm chart for the Kubernetes Agents Operator +home: https://github.com/newrelic/k8s-agents-operator/blob/main/charts/k8s-agents-operator/README.md +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +name: k8s-agents-operator +sources: +- https://github.com/newrelic/k8s-agents-operator +type: application +version: 0.10.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/README.md new file mode 100644 index 000000000..d344832d8 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/README.md @@ -0,0 +1,191 @@ +# k8s-agents-operator + +![Version: 0.10.0](https://img.shields.io/badge/Version-0.10.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.10.0](https://img.shields.io/badge/AppVersion-0.10.0-informational?style=flat-square) + +A Helm chart for the Kubernetes Agents Operator + +**Homepage:** + +## Prerequisites + +[Helm](https://helm.sh) must be installed to use the charts. Please refer to Helm's [documentation](https://helm.sh/docs) to get started. + +## Installation + +### Requirements + +Add the `jetstack` and `k8s-agents-operator` Helm chart repositories: +```shell +helm repo add jetstack https://charts.jetstack.io +helm repo add k8s-agents-operator https://newrelic.github.io/k8s-agents-operator +``` + +Install the [`cert-manager`](https://github.com/cert-manager/cert-manager) Helm chart: +```shell +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --set crds.enabled=true +``` + +### Instrumentation + +Install the [`k8s-agents-operator`](https://github.com/newrelic/k8s-agents-operator) Helm chart: +```shell +helm upgrade --install k8s-agents-operator k8s-agents-operator/k8s-agents-operator \ + --namespace k8s-agents-operator \ + --create-namespace \ + --values your-custom-values.yaml +``` + +### Monitored namespaces + +For each namespace you want the operator to be instrumented, create a secret containing a valid New Relic ingest license key: +```shell +kubectl create secret generic newrelic-key-secret \ + --namespace my-monitored-namespace \ + --from-literal=new_relic_license_key= +``` + +Similarly, for each namespace you need to instrument create the `Instrumentation` custom resource, specifying which APM agents you want to instrument. All available APM agent docker images and corresponding tags are listed on DockerHub: +* [Java](https://hub.docker.com/repository/docker/newrelic/newrelic-java-init/general) +* [Node](https://hub.docker.com/repository/docker/newrelic/newrelic-node-init/general) +* [Python](https://hub.docker.com/repository/docker/newrelic/newrelic-python-init/general) +* [.NET](https://hub.docker.com/repository/docker/newrelic/newrelic-dotnet-init/general) +* [Ruby](https://hub.docker.com/repository/docker/newrelic/newrelic-ruby-init/general) + +```yaml +apiVersion: newrelic.com/v1alpha1 +kind: Instrumentation +metadata: + labels: + app.kubernetes.io/name: instrumentation + app.kubernetes.io/created-by: k8s-agents-operator + name: newrelic-instrumentation +spec: + java: + image: newrelic/newrelic-java-init:latest + # env: + # Example New Relic agent supported environment variables + # - name: NEW_RELIC_LABELS + # value: "environment:auto-injection" + # Example overriding the appName configuration + # - name: NEW_RELIC_POD_NAME + # valueFrom: + # fieldRef: + # fieldPath: metadata.name + # - name: NEW_RELIC_APP_NAME + # value: "$(NEW_RELIC_LABELS)-$(NEW_RELIC_POD_NAME)" + nodejs: + image: newrelic/newrelic-node-init:latest + python: + image: newrelic/newrelic-python-init:latest + dotnet: + image: newrelic/newrelic-dotnet-init:latest + ruby: + image: newrelic/newrelic-ruby-init:latest +``` +In the example above, we show how you can configure the agent settings globally using environment variables. See each agent's configuration documentation for available configuration options: +* [Java](https://docs.newrelic.com/docs/apm/agents/java-agent/configuration/java-agent-configuration-config-file/) +* [Node](https://docs.newrelic.com/docs/apm/agents/nodejs-agent/installation-configuration/nodejs-agent-configuration/) +* [Python](https://docs.newrelic.com/docs/apm/agents/python-agent/configuration/python-agent-configuration/) +* [.NET](https://docs.newrelic.com/docs/apm/agents/net-agent/configuration/net-agent-configuration/) +* [Ruby](https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration/) + +Global agent settings can be overridden in your deployment manifest if a different configuration is required. + +### Annotations + +The `k8s-agents-operator` looks for language-specific annotations when your pods are being scheduled to know which applications you want to monitor. + +Below are the currently supported annotations: +```yaml +instrumentation.newrelic.com/inject-java: "true" +instrumentation.newrelic.com/inject-nodejs: "true" +instrumentation.newrelic.com/inject-python: "true" +instrumentation.newrelic.com/inject-dotnet: "true" +instrumentation.newrelic.com/inject-ruby: "true" +``` + +Example deployment with annotation to instrument the Java agent: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: spring-petclinic +spec: + selector: + matchLabels: + app: spring-petclinic + replicas: 1 + template: + metadata: + labels: + app: spring-petclinic + annotations: + instrumentation.newrelic.com/inject-java: "true" + spec: + containers: + - name: spring-petclinic + image: ghcr.io/pavolloffay/spring-petclinic:latest + ports: + - containerPort: 8080 + env: + - name: NEW_RELIC_APP_NAME + value: spring-petclinic-demo +``` + +## Available Chart Releases + +To see the available charts: +```shell +helm search repo k8s-agents-operator +``` + +If you want to see a list of all available charts and releases, check [index.yaml](https://newrelic.github.io/k8s-agents-operator/index.yaml). + +## Source Code + +* + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| admissionWebhooks | object | `{"create":true}` | Admission webhooks make sure only requests with correctly formatted rules will get into the Operator | +| controllerManager.kubeRbacProxy.image.repository | string | `"gcr.io/kubebuilder/kube-rbac-proxy"` | | +| controllerManager.kubeRbacProxy.image.tag | string | `"v0.14.0"` | | +| controllerManager.kubeRbacProxy.resources.limits.cpu | string | `"500m"` | | +| controllerManager.kubeRbacProxy.resources.limits.memory | string | `"128Mi"` | | +| controllerManager.kubeRbacProxy.resources.requests.cpu | string | `"5m"` | | +| controllerManager.kubeRbacProxy.resources.requests.memory | string | `"64Mi"` | | +| controllerManager.manager.image.pullPolicy | string | `nil` | | +| controllerManager.manager.image.repository | string | `"newrelic/k8s-agents-operator"` | | +| controllerManager.manager.image.tag | string | `nil` | | +| controllerManager.manager.leaderElection | object | `{"enabled":true}` | Enable leader election mechanism for protecting against split brain if multiple operator pods/replicas are started | +| controllerManager.manager.resources.requests.cpu | string | `"100m"` | | +| controllerManager.manager.resources.requests.memory | string | `"64Mi"` | | +| controllerManager.manager.serviceAccount.create | bool | `true` | | +| controllerManager.replicas | int | `1` | | +| kubernetesClusterDomain | string | `"cluster.local"` | | +| metricsService.ports[0].name | string | `"https"` | | +| metricsService.ports[0].port | int | `8443` | | +| metricsService.ports[0].protocol | string | `"TCP"` | | +| metricsService.ports[0].targetPort | string | `"https"` | | +| metricsService.type | string | `"ClusterIP"` | | +| securityContext | object | `{"fsGroup":65532,"runAsGroup":65532,"runAsNonRoot":true,"runAsUser":65532}` | SecurityContext holds pod-level security attributes and common container settings | +| webhookService.ports[0].port | int | `443` | | +| webhookService.ports[0].protocol | string | `"TCP"` | | +| webhookService.ports[0].targetPort | int | `9443` | | +| webhookService.type | string | `"ClusterIP"` | | + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| juanjjaramillo | | | +| csongnr | | | +| dbudziwojskiNR | | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/README.md.gotmpl new file mode 100644 index 000000000..fadd3b971 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/README.md.gotmpl @@ -0,0 +1,157 @@ +{{ template "chart.header" . }} + +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +## Prerequisites + +[Helm](https://helm.sh) must be installed to use the charts. Please refer to Helm's [documentation](https://helm.sh/docs) to get started. + +## Installation + +### Requirements + +Add the `jetstack` and `k8s-agents-operator` Helm chart repositories: +```shell +helm repo add jetstack https://charts.jetstack.io +helm repo add k8s-agents-operator https://newrelic.github.io/k8s-agents-operator +``` + +Install the [`cert-manager`](https://github.com/cert-manager/cert-manager) Helm chart: +```shell +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --set crds.enabled=true +``` + +### Instrumentation + +Install the [`k8s-agents-operator`](https://github.com/newrelic/k8s-agents-operator) Helm chart: +```shell +helm upgrade --install k8s-agents-operator k8s-agents-operator/k8s-agents-operator \ + --namespace k8s-agents-operator \ + --create-namespace \ + --values your-custom-values.yaml +``` + +### Monitored namespaces + +For each namespace you want the operator to be instrumented, create a secret containing a valid New Relic ingest license key: +```shell +kubectl create secret generic newrelic-key-secret \ + --namespace my-monitored-namespace \ + --from-literal=new_relic_license_key= +``` + +Similarly, for each namespace you need to instrument create the `Instrumentation` custom resource, specifying which APM agents you want to instrument. All available APM agent docker images and corresponding tags are listed on DockerHub: +* [Java](https://hub.docker.com/repository/docker/newrelic/newrelic-java-init/general) +* [Node](https://hub.docker.com/repository/docker/newrelic/newrelic-node-init/general) +* [Python](https://hub.docker.com/repository/docker/newrelic/newrelic-python-init/general) +* [.NET](https://hub.docker.com/repository/docker/newrelic/newrelic-dotnet-init/general) +* [Ruby](https://hub.docker.com/repository/docker/newrelic/newrelic-ruby-init/general) + +```yaml +apiVersion: newrelic.com/v1alpha1 +kind: Instrumentation +metadata: + labels: + app.kubernetes.io/name: instrumentation + app.kubernetes.io/created-by: k8s-agents-operator + name: newrelic-instrumentation +spec: + java: + image: newrelic/newrelic-java-init:latest + # env: + # Example New Relic agent supported environment variables + # - name: NEW_RELIC_LABELS + # value: "environment:auto-injection" + # Example overriding the appName configuration + # - name: NEW_RELIC_POD_NAME + # valueFrom: + # fieldRef: + # fieldPath: metadata.name + # - name: NEW_RELIC_APP_NAME + # value: "$(NEW_RELIC_LABELS)-$(NEW_RELIC_POD_NAME)" + nodejs: + image: newrelic/newrelic-node-init:latest + python: + image: newrelic/newrelic-python-init:latest + dotnet: + image: newrelic/newrelic-dotnet-init:latest + ruby: + image: newrelic/newrelic-ruby-init:latest +``` +In the example above, we show how you can configure the agent settings globally using environment variables. See each agent's configuration documentation for available configuration options: +* [Java](https://docs.newrelic.com/docs/apm/agents/java-agent/configuration/java-agent-configuration-config-file/) +* [Node](https://docs.newrelic.com/docs/apm/agents/nodejs-agent/installation-configuration/nodejs-agent-configuration/) +* [Python](https://docs.newrelic.com/docs/apm/agents/python-agent/configuration/python-agent-configuration/) +* [.NET](https://docs.newrelic.com/docs/apm/agents/net-agent/configuration/net-agent-configuration/) +* [Ruby](https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration/) + +Global agent settings can be overridden in your deployment manifest if a different configuration is required. + +### Annotations + +The `k8s-agents-operator` looks for language-specific annotations when your pods are being scheduled to know which applications you want to monitor. + +Below are the currently supported annotations: +```yaml +instrumentation.newrelic.com/inject-java: "true" +instrumentation.newrelic.com/inject-nodejs: "true" +instrumentation.newrelic.com/inject-python: "true" +instrumentation.newrelic.com/inject-dotnet: "true" +instrumentation.newrelic.com/inject-ruby: "true" +``` + +Example deployment with annotation to instrument the Java agent: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: spring-petclinic +spec: + selector: + matchLabels: + app: spring-petclinic + replicas: 1 + template: + metadata: + labels: + app: spring-petclinic + annotations: + instrumentation.newrelic.com/inject-java: "true" + spec: + containers: + - name: spring-petclinic + image: ghcr.io/pavolloffay/spring-petclinic:latest + ports: + - containerPort: 8080 + env: + - name: NEW_RELIC_APP_NAME + value: spring-petclinic-demo +``` + +## Available Chart Releases + +To see the available charts: +```shell +helm search repo k8s-agents-operator +``` + +If you want to see a list of all available charts and releases, check [index.yaml](https://newrelic.github.io/k8s-agents-operator/index.yaml). + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "helm-docs.versionFooter" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/NOTES.txt b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/NOTES.txt new file mode 100644 index 000000000..e3fb91764 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/NOTES.txt @@ -0,0 +1,36 @@ +This project is currently in experimental phases and is provided AS-IS WITHOUT WARRANTY OR DEDICATED SUPPORT. +Issues and contributions should be reported to the project's GitHub. +{{- if (include "k8s-agents-operator.areValuesValid" .) }} +===================================== + + ******** + **************** + ********** **********, + &&&**** ****/((( + &&&&&&& (((((( + &&&&&&&&&& (((((( + &&&&&&&& (((((( + &&&&& (((((( + &&&&& (((((((( + &&&&& .(((((((((( + &&&&&(((((((( + &&&(((, + +Your deployment of the New Relic Agent Operator is complete. +You can check on the progress of this by running the following command: + +kubectl get deployments -o wide -w --namespace {{ .Release.Namespace }} {{ template "k8s-agents-operator.fullname" . }} + +WARNING: This deployment will be incomplete until you configure your Instrumentation custom resource definition. +===================================== + +Please visit https://github.com/newrelic/k8s-agents-operator for instructions on how to create & configure the +Instrumentation custom resource definition required by the Operator. +{{- else }} + +############################################################################## +#### ERROR: You did not set a license key. #### +############################################################################## + +This deployment will be incomplete until you get your ingest license key from New Relic. +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/_helpers.tpl new file mode 100644 index 000000000..43b57a4d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/_helpers.tpl @@ -0,0 +1,80 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "k8s-agents-operator.name" -}} +{{- .Chart.Name | 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 "k8s-agents-operator.fullname" -}} +{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "k8s-agents-operator.chart" -}} +{{- printf "%s" .Chart.Name | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "k8s-agents-operator.labels" -}} +helm.sh/chart: {{ include "k8s-agents-operator.chart" . }} +{{ include "k8s-agents-operator.selectorLabels" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "k8s-agents-operator.selectorLabels" -}} +app.kubernetes.io/name: {{ include "k8s-agents-operator.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "k8s-agents-operator.serviceAccountName" -}} +{{- if .Values.controllerManager.manager.serviceAccount.create }} +{{- default (include "k8s-agents-operator.name" .) .Values.controllerManager.manager.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.controllerManager.manager.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Return the licenseKey +*/}} +{{- define "k8s-agents-operator.licenseKey" -}} +{{- if .Values.global}} + {{- if .Values.global.licenseKey }} + {{- .Values.global.licenseKey -}} + {{- else -}} + {{- .Values.licenseKey | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.licenseKey | default "" -}} +{{- end -}} +{{- end -}} + +{{/* +Returns if the template should render, it checks if the required values are set. +*/}} +{{- define "k8s-agents-operator.areValuesValid" -}} +{{- $licenseKey := include "k8s-agents-operator.licenseKey" . -}} +{{- and (or $licenseKey)}} +{{- end -}} + +{{/* +Controller manager service certificate's secret. +*/}} +{{- define "k8s-agents-operator.certificateSecret" -}} +{{- printf "%s-controller-manager-service-cert" (include "k8s-agents-operator.fullname" .) | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/certmanager.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/certmanager.yaml new file mode 100644 index 000000000..54509f673 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/certmanager.yaml @@ -0,0 +1,17 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-serving-cert + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +spec: + dnsNames: + - '{{ template "k8s-agents-operator.fullname" . }}-webhook-service.{{ .Release.Namespace }}.svc' + - '{{ template "k8s-agents-operator.fullname" . }}-webhook-service.{{ .Release.Namespace }}.svc.{{ .Values.kubernetesClusterDomain }}' + issuerRef: + kind: Issuer + name: '{{ template "k8s-agents-operator.fullname" . }}-selfsigned-issuer' + secretName: {{ template "k8s-agents-operator.certificateSecret" . }} + subject: + organizationalUnits: + - k8s-agents-operator \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/deployment.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/deployment.yaml new file mode 100644 index 000000000..bf19d4e16 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/deployment.yaml @@ -0,0 +1,91 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "k8s-agents-operator.serviceAccountName" . }} + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "k8s-agents-operator.fullname" . }} + labels: + control-plane: controller-manager + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.controllerManager.replicas }} + selector: + matchLabels: + app.kubernetes.io/name: k8s-agents-operator + control-plane: controller-manager + {{- include "k8s-agents-operator.labels" . | nindent 6 }} + template: + metadata: + labels: + app.kubernetes.io/name: k8s-agents-operator + control-plane: controller-manager + {{- include "k8s-agents-operator.labels" . | nindent 8 }} + spec: + containers: + - args: + - --metrics-addr=127.0.0.1:8080 + {{- if .Values.controllerManager.manager.leaderElection.enabled }} + - --enable-leader-election + {{- end }} + - --zap-log-level=info + - --zap-time-encoding=rfc3339nano + env: + - name: KUBERNETES_CLUSTER_DOMAIN + value: {{ quote .Values.kubernetesClusterDomain }} + - name: ENABLE_WEBHOOKS + value: "true" + image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }} + imagePullPolicy: {{ .Values.controllerManager.manager.image.pullPolicy | default "Always" }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10 }} + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=0 + env: + - name: KUBERNETES_CLUSTER_DOMAIN + value: {{ quote .Values.kubernetesClusterDomain }} + image: {{ .Values.controllerManager.kubeRbacProxy.image.repository }}:{{ .Values.controllerManager.kubeRbacProxy.image.tag | default .Chart.AppVersion }} + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: {{- toYaml .Values.controllerManager.kubeRbacProxy.resources | nindent 10 }} + serviceAccountName: {{ template "k8s-agents-operator.serviceAccountName" . }} + terminationGracePeriodSeconds: 10 + {{- if or .Values.admissionWebhooks.create .Values.admissionWebhooks.secretName }} + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: {{ template "k8s-agents-operator.certificateSecret" . }} + {{- end }} + securityContext: +{{ toYaml .Values.securityContext | indent 8 }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/instrumentation-crd.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/instrumentation-crd.yaml new file mode 100644 index 000000000..ae81414fb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/instrumentation-crd.yaml @@ -0,0 +1,1150 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: instrumentations.newrelic.com + annotations: + controller-gen.kubebuilder.io/version: v0.11.3 + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +spec: + group: newrelic.com + names: + kind: Instrumentation + listKind: InstrumentationList + plural: instrumentations + shortNames: + - nragent + - nragents + singular: instrumentation + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Instrumentation is the Schema for the instrumentations API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: InstrumentationSpec defines the desired state of Instrumentation + properties: + dotnet: + description: DotNet defines configuration for dotnet auto-instrumentation. + properties: + env: + description: Env defines DotNet specific env vars. If the former + var had been defined, then the other vars would be ignored. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image is a container image with DotNet agent and + auto-instrumentation. + type: string + type: object + env: + description: 'Env defines common env vars. There are four layers for + env vars'' definitions and the precedence order is: `original container + env vars` > `language specific env vars` > `common env vars` > `instrument + spec configs'' vars`. If the former var had been defined, then the + other vars would be ignored.' + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using + the previously defined environment variables in the container + and any service environment variables. If a variable cannot + be resolved, the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows for escaping + the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the + string literal "$(VAR_NAME)". Escaped references will never + be expanded, regardless of whether the variable exists or + not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot + be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, + status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + exporter: + description: Exporter defines exporter configuration. + properties: + endpoint: + description: Endpoint is address of the collector with OTLP endpoint. + type: string + type: object + go: + description: Go defines configuration for Go auto-instrumentation. + When using Go auto-instrumentation you must provide a value for + the OTEL_GO_AUTO_TARGET_EXE env var via the Instrumentation env + vars or via the instrumentation.opentelemetry.io/otel-go-auto-target-exe + pod annotation. Failure to set this value causes instrumentation + injection to abort, leaving the original pod unchanged. + properties: + env: + description: 'Env defines Go specific env vars. There are four + layers for env vars'' definitions and the precedence order is: + `original container env vars` > `language specific env vars` + > `common env vars` > `instrument spec configs'' vars`. If the + former var had been defined, then the other vars would be ignored.' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image is a container image with Go SDK and auto-instrumentation. + type: string + resourceRequirements: + description: Resources describes the compute resource requirements. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. It can only be + set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + volumeLimitSize: + anyOf: + - type: integer + - type: string + description: VolumeSizeLimit defines size limit for volume used + for auto-instrumentation. The default size is 200Mi. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + java: + description: Java defines configuration for java auto-instrumentation. + properties: + env: + description: Env defines java specific env vars. If the former + var had been defined, then the other vars would be ignored. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image is a container image with javaagent auto-instrumentation + JAR. + type: string + type: object + nodejs: + description: NodeJS defines configuration for nodejs auto-instrumentation. + properties: + env: + description: Env defines nodejs specific env vars. If the former + var had been defined, then the other vars would be ignored. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image is a container image with NodeJS agent and + auto-instrumentation. + type: string + type: object + php: + description: Php defines configuration for php auto-instrumentation. + properties: + env: + description: Env defines Php specific env vars. If the former + var had been defined, then the other vars would be ignored. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image is a container image with Php agent and auto-instrumentation. + type: string + type: object + propagators: + description: Propagators defines inter-process context propagation + configuration. Values in this list will be set in the OTEL_PROPAGATORS + env var. Enum=tracecontext;none + items: + description: Propagator represents the propagation type. + enum: + - tracecontext + - none + type: string + type: array + python: + description: Python defines configuration for python auto-instrumentation. + properties: + env: + description: Env defines python specific env vars. If the former + var had been defined, then the other vars would be ignored. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image is a container image with Python agent and + auto-instrumentation. + type: string + type: object + ruby: + description: Ruby defines configuration for ruby auto-instrumentation. + properties: + env: + description: Env defines Ruby specific env vars. If the former + var had been defined, then the other vars would be ignored. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be a + C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in + the container and any service environment variables. If + a variable cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced to a single + $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless + of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, spec.nodeName, + spec.serviceAccountName, status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of the container: only + resources limits and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, requests.memory + and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + image: + description: Image is a container image with Ruby agent and + auto-instrumentation. + type: string + type: object + resource: + description: Resource defines the configuration for the resource attributes, + as defined by the OpenTelemetry specification. + properties: + addK8sUIDAttributes: + description: AddK8sUIDAttributes defines whether K8s UID attributes + should be collected (e.g. k8s.deployment.uid). + type: boolean + resourceAttributes: + additionalProperties: + type: string + description: 'Attributes defines attributes that are added to + the resource. For example environment: dev' + type: object + type: object + sampler: + description: Sampler defines sampling configuration. + properties: + argument: + description: Argument defines sampler argument. The value depends + on the sampler type. For instance for parentbased_traceidratio + sampler type it is a number in range [0..1] e.g. 0.25. The value + will be set in the OTEL_TRACES_SAMPLER_ARG env var. + type: string + type: + description: Type defines sampler type. The value will be set + in the OTEL_TRACES_SAMPLER env var. The value can be for instance + parentbased_always_on, parentbased_always_off, parentbased_traceidratio... + enum: + - always_on + - always_off + - traceidratio + - parentbased_always_on + - parentbased_always_off + - parentbased_traceidratio + type: string + type: object + type: object + status: + description: InstrumentationStatus defines the observed state of Instrumentation + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/leader-election-rbac.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/leader-election-rbac.yaml new file mode 100644 index 000000000..57a5be3a3 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/leader-election-rbac.yaml @@ -0,0 +1,49 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-leader-election-role + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps/status + verbs: + - get + - update + - patch +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-leader-election-rolebinding + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: '{{ template "k8s-agents-operator.fullname" . }}-leader-election-role' +subjects: +- kind: ServiceAccount + name: '{{ template "k8s-agents-operator.serviceAccountName" . }}' + namespace: '{{ .Release.Namespace }}' \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/manager-rbac.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/manager-rbac.yaml new file mode 100644 index 000000000..7a1d9d3bf --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/manager-rbac.yaml @@ -0,0 +1,76 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-manager-role + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - list + - watch +- apiGroups: + - apps + resources: + - replicasets + verbs: + - get + - list + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - list + - update +- apiGroups: + - newrelic.com + resources: + - instrumentations + verbs: + - get + - list + - patch + - update + - watch +- apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-manager-rolebinding + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: '{{ template "k8s-agents-operator.fullname" . }}-manager-role' +subjects: +- kind: ServiceAccount + name: '{{ template "k8s-agents-operator.serviceAccountName" . }}' + namespace: '{{ .Release.Namespace }}' \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/mutating-webhook-configuration.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/mutating-webhook-configuration.yaml new file mode 100644 index 000000000..f37ad6a79 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/mutating-webhook-configuration.yaml @@ -0,0 +1,49 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-mutating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "k8s-agents-operator.fullname" . }}-serving-cert + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ template "k8s-agents-operator.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /mutate-newrelic-com-v1alpha1-instrumentation + failurePolicy: Fail + name: instrumentation.kb.io + rules: + - apiGroups: + - newrelic.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - instrumentations + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ template "k8s-agents-operator.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /mutate-v1-pod + failurePolicy: Ignore + name: mpod.kb.io + rules: + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - pods + sideEffects: None \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/newrelic_license_secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/newrelic_license_secret.yaml new file mode 100644 index 000000000..db2c35f72 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/newrelic_license_secret.yaml @@ -0,0 +1,14 @@ +{{- $licenseKey := include "k8s-agents-operator.licenseKey" . -}} +{{- if $licenseKey }} +apiVersion: v1 +kind: Secret +metadata: + name: "newrelic-key-secret" + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ include "k8s-agents-operator.chart" . }} + app.kubernetes.io/instance: {{ .Release.Name }} +type: Opaque +data: + new_relic_license_key: {{ $licenseKey | b64enc }} +{{- end }} \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/proxy-rbac.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/proxy-rbac.yaml new file mode 100644 index 000000000..af583f595 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/proxy-rbac.yaml @@ -0,0 +1,34 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-proxy-role + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-proxy-rolebinding + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: '{{ template "k8s-agents-operator.fullname" . }}-proxy-role' +subjects: +- kind: ServiceAccount + name: '{{ template "k8s-agents-operator.serviceAccountName" . }}' + namespace: '{{ .Release.Namespace }}' \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/reader-rbac.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/reader-rbac.yaml new file mode 100644 index 000000000..6482ff0db --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/reader-rbac.yaml @@ -0,0 +1,11 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-metrics-reader + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +rules: +- nonResourceURLs: + - /metrics + verbs: + - get \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/selfsigned-issuer.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/selfsigned-issuer.yaml new file mode 100644 index 000000000..31c0cc79f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/selfsigned-issuer.yaml @@ -0,0 +1,8 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-selfsigned-issuer + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +spec: + selfSigned: {} \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/service.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/service.yaml new file mode 100644 index 000000000..892b1b3e8 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "k8s-agents-operator.fullname" . }} + labels: + control-plane: controller-manager + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +spec: + type: {{ .Values.metricsService.type }} + selector: + app.kubernetes.io/name: {{ include "k8s-agents-operator.chart" . }} + control-plane: controller-manager + {{- include "k8s-agents-operator.labels" . | nindent 4 }} + ports: + {{- .Values.metricsService.ports | toYaml | nindent 2 -}} \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/validating-webhook-configuration.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/validating-webhook-configuration.yaml new file mode 100644 index 000000000..f98608b7e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/validating-webhook-configuration.yaml @@ -0,0 +1,48 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-validating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "k8s-agents-operator.fullname" . }}-serving-cert + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ template "k8s-agents-operator.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /validate-newrelic-com-v1alpha1-instrumentation + failurePolicy: Fail + name: vinstrumentationcreateupdate.kb.io + rules: + - apiGroups: + - newrelic.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - instrumentations + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ template "k8s-agents-operator.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /validate-newrelic-com-v1alpha1-instrumentation + failurePolicy: Ignore + name: vinstrumentationdelete.kb.io + rules: + - apiGroups: + - newrelic.com + apiVersions: + - v1alpha1 + operations: + - DELETE + resources: + - instrumentations + sideEffects: None \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/webhook-service.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/webhook-service.yaml new file mode 100644 index 000000000..d2197c679 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/templates/webhook-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "k8s-agents-operator.fullname" . }}-webhook-service + labels: + {{- include "k8s-agents-operator.labels" . | nindent 4 }} +spec: + type: {{ .Values.webhookService.type }} + selector: + app.kubernetes.io/name: {{ include "k8s-agents-operator.chart" . }} + app.kubernetes.io/name: k8s-agents-operator + control-plane: controller-manager + {{- include "k8s-agents-operator.labels" . | nindent 4 }} + ports: + {{- .Values.webhookService.ports | toYaml | nindent 2 -}} \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/values.yaml new file mode 100644 index 000000000..7cae82fb8 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/k8s-agents-operator/values.yaml @@ -0,0 +1,62 @@ +# -- Ingest license key to use +# licenseKey: + +controllerManager: + replicas: 1 + + kubeRbacProxy: + image: + repository: gcr.io/kubebuilder/kube-rbac-proxy + tag: v0.14.0 + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + + manager: + image: + repository: newrelic/k8s-agents-operator + tag: + pullPolicy: + resources: + requests: + cpu: 100m + memory: 64Mi + serviceAccount: + create: true + # -- Source: https://docs.openshift.com/container-platform/4.10/operators/operator_sdk/osdk-leader-election.html + # -- Enable leader election mechanism for protecting against split brain if multiple operator pods/replicas are started + leaderElection: + enabled: true + +kubernetesClusterDomain: cluster.local + +metricsService: + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + type: ClusterIP + +webhookService: + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + type: ClusterIP + +# -- Source: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +# -- SecurityContext holds pod-level security attributes and common container settings +securityContext: + runAsGroup: 65532 + runAsNonRoot: true + runAsUser: 65532 + fsGroup: 65532 + +# -- Admission webhooks make sure only requests with correctly formatted rules will get into the Operator +admissionWebhooks: + create: true diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/Chart.yaml new file mode 100644 index 000000000..a86cd07e9 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/Chart.yaml @@ -0,0 +1,26 @@ +annotations: + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: Chart Source + url: https://github.com/prometheus-community/helm-charts +apiVersion: v2 +appVersion: 2.10.0 +description: Install kube-state-metrics to generate and expose cluster-level metrics +home: https://github.com/kubernetes/kube-state-metrics/ +keywords: +- metric +- monitoring +- prometheus +- kubernetes +maintainers: +- email: tariq.ibrahim@mulesoft.com + name: tariq1890 +- email: manuel@rueg.eu + name: mrueg +- email: david@0xdc.me + name: dotdc +name: kube-state-metrics +sources: +- https://github.com/kubernetes/kube-state-metrics/ +type: application +version: 5.12.1 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/README.md new file mode 100644 index 000000000..843be89e6 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/README.md @@ -0,0 +1,85 @@ +# kube-state-metrics Helm Chart + +Installs the [kube-state-metrics agent](https://github.com/kubernetes/kube-state-metrics). + +## Get Repository Info + +```console +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update +``` + +_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + + +## Install Chart + +```console +helm install [RELEASE_NAME] prometheus-community/kube-state-metrics [flags] +``` + +_See [configuration](#configuration) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Uninstall Chart + +```console +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +## Upgrading Chart + +```console +helm upgrade [RELEASE_NAME] prometheus-community/kube-state-metrics [flags] +``` + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### Migrating from stable/kube-state-metrics and kubernetes/kube-state-metrics + +You can upgrade in-place: + +1. [get repository info](#get-repository-info) +1. [upgrade](#upgrading-chart) your existing release name using the new chart repository + +## Upgrading to v3.0.0 + +v3.0.0 includes kube-state-metrics v2.0, see the [changelog](https://github.com/kubernetes/kube-state-metrics/blob/release-2.0/CHANGELOG.md) for major changes on the application-side. + +The upgraded chart now the following changes: + +* Dropped support for helm v2 (helm v3 or later is required) +* collectors key was renamed to resources +* namespace key was renamed to namespaces + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments: + +```console +helm show values prometheus-community/kube-state-metrics +``` + +### kube-rbac-proxy + +You can enable `kube-state-metrics` endpoint protection using `kube-rbac-proxy`. By setting `kubeRBACProxy.enabled: true`, this chart will deploy one RBAC proxy container per endpoint (metrics & telemetry). +To authorize access, authenticate your requests (via a `ServiceAccount` for example) with a `ClusterRole` attached such as: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kube-state-metrics-read +rules: + - apiGroups: [ "" ] + resources: ["services/kube-state-metrics"] + verbs: + - get +``` + +See [kube-rbac-proxy examples](https://github.com/brancz/kube-rbac-proxy/tree/master/examples/resource-attributes) for more details. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/NOTES.txt b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/NOTES.txt new file mode 100644 index 000000000..3589c24ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/NOTES.txt @@ -0,0 +1,23 @@ +kube-state-metrics is a simple service that listens to the Kubernetes API server and generates metrics about the state of the objects. +The exposed metrics can be found here: +https://github.com/kubernetes/kube-state-metrics/blob/master/docs/README.md#exposed-metrics + +The metrics are exported on the HTTP endpoint /metrics on the listening port. +In your case, {{ template "kube-state-metrics.fullname" . }}.{{ template "kube-state-metrics.namespace" . }}.svc.cluster.local:{{ .Values.service.port }}/metrics + +They are served either as plaintext or protobuf depending on the Accept header. +They are designed to be consumed either by Prometheus itself or by a scraper that is compatible with scraping a Prometheus client endpoint. + +{{- if .Values.kubeRBACProxy.enabled}} + +kube-rbac-proxy endpoint protections is enabled: +- Metrics endpoints are now HTTPS +- Ensure that the client authenticates the requests (e.g. via service account) with the following role permissions: +``` +rules: + - apiGroups: [ "" ] + resources: ["services/{{ template "kube-state-metrics.fullname" . }}"] + verbs: + - get +``` +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/_helpers.tpl new file mode 100644 index 000000000..a4358c87a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/_helpers.tpl @@ -0,0 +1,156 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "kube-state-metrics.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 "kube-state-metrics.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 the name of the service account to use +*/}} +{{- define "kube-state-metrics.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "kube-state-metrics.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "kube-state-metrics.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kube-state-metrics.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Generate basic labels +*/}} +{{- define "kube-state-metrics.labels" }} +helm.sh/chart: {{ template "kube-state-metrics.chart" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: metrics +app.kubernetes.io/part-of: {{ template "kube-state-metrics.name" . }} +{{- include "kube-state-metrics.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels }} +{{- end }} +{{- if .Values.releaseLabel }} +release: {{ .Release.Name }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "kube-state-metrics.selectorLabels" }} +{{- if .Values.selectorOverride }} +{{ toYaml .Values.selectorOverride }} +{{- else }} +app.kubernetes.io/name: {{ include "kube-state-metrics.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} +{{- end }} + +{{/* Sets default scrape limits for servicemonitor */}} +{{- define "servicemonitor.scrapeLimits" -}} +{{- with .sampleLimit }} +sampleLimit: {{ . }} +{{- end }} +{{- with .targetLimit }} +targetLimit: {{ . }} +{{- end }} +{{- with .labelLimit }} +labelLimit: {{ . }} +{{- end }} +{{- with .labelNameLengthLimit }} +labelNameLengthLimit: {{ . }} +{{- end }} +{{- with .labelValueLengthLimit }} +labelValueLengthLimit: {{ . }} +{{- end }} +{{- end -}} + +{{/* +Formats imagePullSecrets. Input is (dict "Values" .Values "imagePullSecrets" .{specific imagePullSecrets}) +*/}} +{{- define "kube-state-metrics.imagePullSecrets" -}} +{{- range (concat .Values.global.imagePullSecrets .imagePullSecrets) }} + {{- if eq (typeOf .) "map[string]interface {}" }} +- {{ toYaml . | trim }} + {{- else }} +- name: {{ . }} + {{- end }} +{{- end }} +{{- end -}} + +{{/* +The image to use for kube-state-metrics +*/}} +{{- define "kube-state-metrics.image" -}} +{{- if .Values.image.sha }} +{{- if .Values.global.imageRegistry }} +{{- printf "%s/%s:%s@%s" .Values.global.imageRegistry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) .Values.image.sha }} +{{- else }} +{{- printf "%s/%s:%s@%s" .Values.image.registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) .Values.image.sha }} +{{- end }} +{{- else }} +{{- if .Values.global.imageRegistry }} +{{- printf "%s/%s:%s" .Values.global.imageRegistry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }} +{{- else }} +{{- printf "%s/%s:%s" .Values.image.registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +The image to use for kubeRBACProxy +*/}} +{{- define "kubeRBACProxy.image" -}} +{{- if .Values.kubeRBACProxy.image.sha }} +{{- if .Values.global.imageRegistry }} +{{- printf "%s/%s:%s@%s" .Values.global.imageRegistry .Values.kubeRBACProxy.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.kubeRBACProxy.image.tag) .Values.kubeRBACProxy.image.sha }} +{{- else }} +{{- printf "%s/%s:%s@%s" .Values.kubeRBACProxy.image.registry .Values.kubeRBACProxy.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.kubeRBACProxy.image.tag) .Values.kubeRBACProxy.image.sha }} +{{- end }} +{{- else }} +{{- if .Values.global.imageRegistry }} +{{- printf "%s/%s:%s" .Values.global.imageRegistry .Values.kubeRBACProxy.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.kubeRBACProxy.image.tag) }} +{{- else }} +{{- printf "%s/%s:%s" .Values.kubeRBACProxy.image.registry .Values.kubeRBACProxy.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.kubeRBACProxy.image.tag) }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml new file mode 100644 index 000000000..025cd47a8 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.networkPolicy.enabled (eq .Values.networkPolicy.flavor "cilium") }} +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + {{- if .Values.annotations }} + annotations: + {{ toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +spec: + endpointSelector: + matchLabels: + {{- include "kube-state-metrics.selectorLabels" . | indent 6 }} + egress: + {{- if and .Values.networkPolicy.cilium .Values.networkPolicy.cilium.kubeApiServerSelector }} + {{ toYaml .Values.networkPolicy.cilium.kubeApiServerSelector | nindent 6 }} + {{- else }} + - toEntities: + - kube-apiserver + {{- end }} + ingress: + - toPorts: + - ports: + - port: {{ .Values.service.port | quote }} + protocol: TCP + {{- if .Values.selfMonitor.enabled }} + - port: {{ .Values.selfMonitor.telemetryPort | default 8081 | quote }} + protocol: TCP + {{ end }} +{{ end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..cf9f628d0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.rbac.create .Values.rbac.useClusterRole -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: {{ template "kube-state-metrics.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole +{{- if .Values.rbac.useExistingRole }} + name: {{ .Values.rbac.useExistingRole }} +{{- else }} + name: {{ template "kube-state-metrics.fullname" . }} +{{- end }} +subjects: +- kind: ServiceAccount + name: {{ template "kube-state-metrics.serviceAccountName" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/crs-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/crs-configmap.yaml new file mode 100644 index 000000000..d38a75a51 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/crs-configmap.yaml @@ -0,0 +1,16 @@ +{{- if .Values.customResourceState.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "kube-state-metrics.fullname" . }}-customresourcestate-config + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + {{- if .Values.annotations }} + annotations: + {{ toYaml .Values.annotations | nindent 4 }} + {{- end }} +data: + config.yaml: | + {{- toYaml .Values.customResourceState.config | nindent 4 }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/deployment.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/deployment.yaml new file mode 100644 index 000000000..31aa61018 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/deployment.yaml @@ -0,0 +1,279 @@ +apiVersion: apps/v1 +{{- if .Values.autosharding.enabled }} +kind: StatefulSet +{{- else }} +kind: Deployment +{{- end }} +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + {{- if .Values.annotations }} + annotations: +{{ toYaml .Values.annotations | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "kube-state-metrics.selectorLabels" . | indent 6 }} + replicas: {{ .Values.replicas }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + {{- if .Values.autosharding.enabled }} + serviceName: {{ template "kube-state-metrics.fullname" . }} + volumeClaimTemplates: [] + {{- end }} + template: + metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 8 }} + {{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + hostNetwork: {{ .Values.hostNetwork }} + serviceAccountName: {{ template "kube-state-metrics.serviceAccountName" . }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + containers: + {{- $httpPort := ternary 9090 (.Values.service.port | default 8080) .Values.kubeRBACProxy.enabled}} + {{- $telemetryPort := ternary 9091 (.Values.selfMonitor.telemetryPort | default 8081) .Values.kubeRBACProxy.enabled}} + - name: {{ template "kube-state-metrics.name" . }} + {{- if .Values.autosharding.enabled }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- end }} + args: + {{- if .Values.extraArgs }} + {{- .Values.extraArgs | toYaml | nindent 8 }} + {{- end }} + - --port={{ $httpPort }} + {{- if .Values.collectors }} + - --resources={{ .Values.collectors | join "," }} + {{- end }} + {{- if .Values.metricLabelsAllowlist }} + - --metric-labels-allowlist={{ .Values.metricLabelsAllowlist | join "," }} + {{- end }} + {{- if .Values.metricAnnotationsAllowList }} + - --metric-annotations-allowlist={{ .Values.metricAnnotationsAllowList | join "," }} + {{- end }} + {{- if .Values.metricAllowlist }} + - --metric-allowlist={{ .Values.metricAllowlist | join "," }} + {{- end }} + {{- if .Values.metricDenylist }} + - --metric-denylist={{ .Values.metricDenylist | join "," }} + {{- end }} + {{- $namespaces := list }} + {{- if .Values.namespaces }} + {{- range $ns := join "," .Values.namespaces | split "," }} + {{- $namespaces = append $namespaces (tpl $ns $) }} + {{- end }} + {{- end }} + {{- if .Values.releaseNamespace }} + {{- $namespaces = append $namespaces ( include "kube-state-metrics.namespace" . ) }} + {{- end }} + {{- if $namespaces }} + - --namespaces={{ $namespaces | mustUniq | join "," }} + {{- end }} + {{- if .Values.namespacesDenylist }} + - --namespaces-denylist={{ tpl (.Values.namespacesDenylist | join ",") $ }} + {{- end }} + {{- if .Values.autosharding.enabled }} + - --pod=$(POD_NAME) + - --pod-namespace=$(POD_NAMESPACE) + {{- end }} + {{- if .Values.kubeconfig.enabled }} + - --kubeconfig=/opt/k8s/.kube/config + {{- end }} + {{- if .Values.kubeRBACProxy.enabled }} + - --telemetry-host=127.0.0.1 + - --telemetry-port={{ $telemetryPort }} + {{- else }} + {{- if .Values.selfMonitor.telemetryHost }} + - --telemetry-host={{ .Values.selfMonitor.telemetryHost }} + {{- end }} + {{- if .Values.selfMonitor.telemetryPort }} + - --telemetry-port={{ $telemetryPort }} + {{- end }} + {{- if .Values.customResourceState.enabled }} + - --custom-resource-state-config-file=/etc/customresourcestate/config.yaml + {{- end }} + {{- end }} + {{- if or (.Values.kubeconfig.enabled) (.Values.customResourceState.enabled) (.Values.volumeMounts) }} + volumeMounts: + {{- if .Values.kubeconfig.enabled }} + - name: kubeconfig + mountPath: /opt/k8s/.kube/ + readOnly: true + {{- end }} + {{- if .Values.customResourceState.enabled }} + - name: customresourcestate-config + mountPath: /etc/customresourcestate + readOnly: true + {{- end }} + {{- if .Values.volumeMounts }} +{{ toYaml .Values.volumeMounts | indent 8 }} + {{- end }} + {{- end }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + image: {{ include "kube-state-metrics.image" . }} + {{- if eq .Values.kubeRBACProxy.enabled false }} + ports: + - containerPort: {{ .Values.service.port | default 8080}} + name: "http" + {{- if .Values.selfMonitor.enabled }} + - containerPort: {{ $telemetryPort }} + name: "metrics" + {{- end }} + {{- end }} + livenessProbe: + httpGet: + path: /healthz + port: {{ $httpPort }} + initialDelaySeconds: 5 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: / + port: {{ $httpPort }} + initialDelaySeconds: 5 + timeoutSeconds: 5 + {{- if .Values.resources }} + resources: +{{ toYaml .Values.resources | indent 10 }} +{{- end }} +{{- if .Values.containerSecurityContext }} + securityContext: +{{ toYaml .Values.containerSecurityContext | indent 10 }} +{{- end }} + {{- if .Values.kubeRBACProxy.enabled }} + - name: kube-rbac-proxy-http + args: + {{- if .Values.kubeRBACProxy.extraArgs }} + {{- .Values.kubeRBACProxy.extraArgs | toYaml | nindent 8 }} + {{- end }} + - --secure-listen-address=:{{ .Values.service.port | default 8080}} + - --upstream=http://127.0.0.1:{{ $httpPort }}/ + - --proxy-endpoints-port=8888 + - --config-file=/etc/kube-rbac-proxy-config/config-file.yaml + volumeMounts: + - name: kube-rbac-proxy-config + mountPath: /etc/kube-rbac-proxy-config + {{- with .Values.kubeRBACProxy.volumeMounts }} + {{- toYaml . | nindent 10 }} + {{- end }} + imagePullPolicy: {{ .Values.kubeRBACProxy.image.pullPolicy }} + image: {{ include "kubeRBACProxy.image" . }} + ports: + - containerPort: {{ .Values.service.port | default 8080}} + name: "http" + - containerPort: 8888 + name: "http-healthz" + readinessProbe: + httpGet: + scheme: HTTPS + port: 8888 + path: healthz + initialDelaySeconds: 5 + timeoutSeconds: 5 + {{- if .Values.kubeRBACProxy.resources }} + resources: +{{ toYaml .Values.kubeRBACProxy.resources | indent 10 }} +{{- end }} +{{- if .Values.kubeRBACProxy.containerSecurityContext }} + securityContext: +{{ toYaml .Values.kubeRBACProxy.containerSecurityContext | indent 10 }} +{{- end }} + {{- if .Values.selfMonitor.enabled }} + - name: kube-rbac-proxy-telemetry + args: + {{- if .Values.kubeRBACProxy.extraArgs }} + {{- .Values.kubeRBACProxy.extraArgs | toYaml | nindent 8 }} + {{- end }} + - --secure-listen-address=:{{ .Values.selfMonitor.telemetryPort | default 8081 }} + - --upstream=http://127.0.0.1:{{ $telemetryPort }}/ + - --proxy-endpoints-port=8889 + - --config-file=/etc/kube-rbac-proxy-config/config-file.yaml + volumeMounts: + - name: kube-rbac-proxy-config + mountPath: /etc/kube-rbac-proxy-config + {{- with .Values.kubeRBACProxy.volumeMounts }} + {{- toYaml . | nindent 10 }} + {{- end }} + imagePullPolicy: {{ .Values.kubeRBACProxy.image.pullPolicy }} + image: {{ include "kubeRBACProxy.image" . }} + ports: + - containerPort: {{ .Values.selfMonitor.telemetryPort | default 8081 }} + name: "metrics" + - containerPort: 8889 + name: "metrics-healthz" + readinessProbe: + httpGet: + scheme: HTTPS + port: 8889 + path: healthz + initialDelaySeconds: 5 + timeoutSeconds: 5 + {{- if .Values.kubeRBACProxy.resources }} + resources: +{{ toYaml .Values.kubeRBACProxy.resources | indent 10 }} +{{- end }} +{{- if .Values.kubeRBACProxy.containerSecurityContext }} + securityContext: +{{ toYaml .Values.kubeRBACProxy.containerSecurityContext | indent 10 }} +{{- end }} + {{- end }} + {{- end }} +{{- if or .Values.imagePullSecrets .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- include "kube-state-metrics.imagePullSecrets" (dict "Values" .Values "imagePullSecrets" .Values.imagePullSecrets) | indent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.topologySpreadConstraints | indent 8 }} + {{- end }} + {{- if or (.Values.kubeconfig.enabled) (.Values.customResourceState.enabled) (.Values.volumes) (.Values.kubeRBACProxy.enabled) }} + volumes: + {{- if .Values.kubeconfig.enabled}} + - name: kubeconfig + secret: + secretName: {{ template "kube-state-metrics.fullname" . }}-kubeconfig + {{- end }} + {{- if .Values.kubeRBACProxy.enabled}} + - name: kube-rbac-proxy-config + configMap: + name: {{ template "kube-state-metrics.fullname" . }}-rbac-config + {{- end }} + {{- if .Values.customResourceState.enabled}} + - name: customresourcestate-config + configMap: + name: {{ template "kube-state-metrics.fullname" . }}-customresourcestate-config + {{- end }} + {{- if .Values.volumes }} +{{ toYaml .Values.volumes | indent 8 }} + {{- end }} + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/extra-manifests.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/extra-manifests.yaml new file mode 100644 index 000000000..567f7bf32 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/extra-manifests.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraManifests }} +--- +{{ tpl (toYaml .) $ }} +{{ end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/kubeconfig-secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/kubeconfig-secret.yaml new file mode 100644 index 000000000..6af008450 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/kubeconfig-secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.kubeconfig.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kube-state-metrics.fullname" . }}-kubeconfig + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +type: Opaque +data: + config: '{{ .Values.kubeconfig.secret }}' +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/networkpolicy.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/networkpolicy.yaml new file mode 100644 index 000000000..309b38ec5 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/networkpolicy.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.networkPolicy.enabled (eq .Values.networkPolicy.flavor "kubernetes") }} +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + {{- if .Values.annotations }} + annotations: + {{ toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +spec: + {{- if .Values.networkPolicy.egress }} + ## Deny all egress by default + egress: + {{- toYaml .Values.networkPolicy.egress | nindent 4 }} + {{- end }} + ingress: + {{- if .Values.networkPolicy.ingress }} + {{- toYaml .Values.networkPolicy.ingress | nindent 4 }} + {{- else }} + ## Allow ingress on default ports by default + - ports: + - port: {{ .Values.service.port | default 8080 }} + protocol: TCP + {{- if .Values.selfMonitor.enabled }} + {{- $telemetryPort := ternary 9091 (.Values.selfMonitor.telemetryPort | default 8081) .Values.kubeRBACProxy.enabled}} + - port: {{ $telemetryPort }} + protocol: TCP + {{- end }} + {{- end }} + podSelector: + {{- if .Values.networkPolicy.podSelector }} + {{- toYaml .Values.networkPolicy.podSelector | nindent 4 }} + {{- else }} + matchLabels: + {{- include "kube-state-metrics.selectorLabels" . | indent 6 }} + {{- end }} + policyTypes: + - Ingress + - Egress +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/pdb.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/pdb.yaml new file mode 100644 index 000000000..3771b511d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/pdb.yaml @@ -0,0 +1,18 @@ +{{- if .Values.podDisruptionBudget -}} +{{ if $.Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" -}} +apiVersion: policy/v1 +{{- else -}} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/podsecuritypolicy.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..8905e113e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/podsecuritypolicy.yaml @@ -0,0 +1,39 @@ +{{- if and .Values.podSecurityPolicy.enabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +{{- if .Values.podSecurityPolicy.annotations }} + annotations: +{{ toYaml .Values.podSecurityPolicy.annotations | indent 4 }} +{{- end }} +spec: + privileged: false + volumes: + - 'secret' +{{- if .Values.podSecurityPolicy.additionalVolumes }} +{{ toYaml .Values.podSecurityPolicy.additionalVolumes | indent 4 }} +{{- end }} + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/psp-clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/psp-clusterrole.yaml new file mode 100644 index 000000000..654e4a3d5 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/psp-clusterrole.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.podSecurityPolicy.enabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: psp-{{ template "kube-state-metrics.fullname" . }} +rules: +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare "> 1.15.0-0" $kubeTargetVersion }} +- apiGroups: ['policy'] +{{- else }} +- apiGroups: ['extensions'] +{{- end }} + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "kube-state-metrics.fullname" . }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml new file mode 100644 index 000000000..5b62a18bd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.podSecurityPolicy.enabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: psp-{{ template "kube-state-metrics.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: psp-{{ template "kube-state-metrics.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "kube-state-metrics.serviceAccountName" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/rbac-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/rbac-configmap.yaml new file mode 100644 index 000000000..671dc9d66 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/rbac-configmap.yaml @@ -0,0 +1,22 @@ +{{- if .Values.kubeRBACProxy.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "kube-state-metrics.fullname" . }}-rbac-config + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + {{- if .Values.annotations }} + annotations: + {{ toYaml .Values.annotations | nindent 4 }} + {{- end }} +data: + config-file.yaml: |+ + authorization: + resourceAttributes: + namespace: {{ template "kube-state-metrics.namespace" . }} + apiVersion: v1 + resource: services + subresource: {{ template "kube-state-metrics.fullname" . }} + name: {{ template "kube-state-metrics.fullname" . }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/role.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/role.yaml new file mode 100644 index 000000000..d33687f2d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/role.yaml @@ -0,0 +1,212 @@ +{{- if and (eq .Values.rbac.create true) (not .Values.rbac.useExistingRole) -}} +{{- range (ternary (join "," .Values.namespaces | split "," ) (list "") (eq $.Values.rbac.useClusterRole false)) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +{{- if eq $.Values.rbac.useClusterRole false }} +kind: Role +{{- else }} +kind: ClusterRole +{{- end }} +metadata: + labels: + {{- include "kube-state-metrics.labels" $ | indent 4 }} + name: {{ template "kube-state-metrics.fullname" $ }} +{{- if eq $.Values.rbac.useClusterRole false }} + namespace: {{ . }} +{{- end }} +rules: +{{ if has "certificatesigningrequests" $.Values.collectors }} +- apiGroups: ["certificates.k8s.io"] + resources: + - certificatesigningrequests + verbs: ["list", "watch"] +{{ end -}} +{{ if has "configmaps" $.Values.collectors }} +- apiGroups: [""] + resources: + - configmaps + verbs: ["list", "watch"] +{{ end -}} +{{ if has "cronjobs" $.Values.collectors }} +- apiGroups: ["batch"] + resources: + - cronjobs + verbs: ["list", "watch"] +{{ end -}} +{{ if has "daemonsets" $.Values.collectors }} +- apiGroups: ["extensions", "apps"] + resources: + - daemonsets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "deployments" $.Values.collectors }} +- apiGroups: ["extensions", "apps"] + resources: + - deployments + verbs: ["list", "watch"] +{{ end -}} +{{ if has "endpoints" $.Values.collectors }} +- apiGroups: [""] + resources: + - endpoints + verbs: ["list", "watch"] +{{ end -}} +{{ if has "endpointslices" $.Values.collectors }} +- apiGroups: ["discovery.k8s.io"] + resources: + - endpointslices + verbs: ["list", "watch"] +{{ end -}} +{{ if has "horizontalpodautoscalers" $.Values.collectors }} +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: ["list", "watch"] +{{ end -}} +{{ if has "ingresses" $.Values.collectors }} +- apiGroups: ["extensions", "networking.k8s.io"] + resources: + - ingresses + verbs: ["list", "watch"] +{{ end -}} +{{ if has "jobs" $.Values.collectors }} +- apiGroups: ["batch"] + resources: + - jobs + verbs: ["list", "watch"] +{{ end -}} +{{ if has "leases" $.Values.collectors }} +- apiGroups: ["coordination.k8s.io"] + resources: + - leases + verbs: ["list", "watch"] +{{ end -}} +{{ if has "limitranges" $.Values.collectors }} +- apiGroups: [""] + resources: + - limitranges + verbs: ["list", "watch"] +{{ end -}} +{{ if has "mutatingwebhookconfigurations" $.Values.collectors }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: + - mutatingwebhookconfigurations + verbs: ["list", "watch"] +{{ end -}} +{{ if has "namespaces" $.Values.collectors }} +- apiGroups: [""] + resources: + - namespaces + verbs: ["list", "watch"] +{{ end -}} +{{ if has "networkpolicies" $.Values.collectors }} +- apiGroups: ["networking.k8s.io"] + resources: + - networkpolicies + verbs: ["list", "watch"] +{{ end -}} +{{ if has "nodes" $.Values.collectors }} +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +{{ end -}} +{{ if has "persistentvolumeclaims" $.Values.collectors }} +- apiGroups: [""] + resources: + - persistentvolumeclaims + verbs: ["list", "watch"] +{{ end -}} +{{ if has "persistentvolumes" $.Values.collectors }} +- apiGroups: [""] + resources: + - persistentvolumes + verbs: ["list", "watch"] +{{ end -}} +{{ if has "poddisruptionbudgets" $.Values.collectors }} +- apiGroups: ["policy"] + resources: + - poddisruptionbudgets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "pods" $.Values.collectors }} +- apiGroups: [""] + resources: + - pods + verbs: ["list", "watch"] +{{ end -}} +{{ if has "replicasets" $.Values.collectors }} +- apiGroups: ["extensions", "apps"] + resources: + - replicasets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "replicationcontrollers" $.Values.collectors }} +- apiGroups: [""] + resources: + - replicationcontrollers + verbs: ["list", "watch"] +{{ end -}} +{{ if has "resourcequotas" $.Values.collectors }} +- apiGroups: [""] + resources: + - resourcequotas + verbs: ["list", "watch"] +{{ end -}} +{{ if has "secrets" $.Values.collectors }} +- apiGroups: [""] + resources: + - secrets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "services" $.Values.collectors }} +- apiGroups: [""] + resources: + - services + verbs: ["list", "watch"] +{{ end -}} +{{ if has "statefulsets" $.Values.collectors }} +- apiGroups: ["apps"] + resources: + - statefulsets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "storageclasses" $.Values.collectors }} +- apiGroups: ["storage.k8s.io"] + resources: + - storageclasses + verbs: ["list", "watch"] +{{ end -}} +{{ if has "validatingwebhookconfigurations" $.Values.collectors }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: + - validatingwebhookconfigurations + verbs: ["list", "watch"] +{{ end -}} +{{ if has "volumeattachments" $.Values.collectors }} +- apiGroups: ["storage.k8s.io"] + resources: + - volumeattachments + verbs: ["list", "watch"] +{{ end -}} +{{- if $.Values.kubeRBACProxy.enabled }} +- apiGroups: ["authentication.k8s.io"] + resources: + - tokenreviews + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: + - subjectaccessreviews + verbs: ["create"] +{{- end }} +{{- if $.Values.customResourceState.enabled }} +- apiGroups: ["apiextensions.k8s.io"] + resources: + - customresourcedefinitions + verbs: ["list", "watch"] +{{- end }} +{{ if $.Values.rbac.extraRules }} +{{ toYaml $.Values.rbac.extraRules }} +{{ end }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/rolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/rolebinding.yaml new file mode 100644 index 000000000..330651b73 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/rolebinding.yaml @@ -0,0 +1,24 @@ +{{- if and (eq .Values.rbac.create true) (eq .Values.rbac.useClusterRole false) -}} +{{- range (join "," $.Values.namespaces) | split "," }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + {{- include "kube-state-metrics.labels" $ | indent 4 }} + name: {{ template "kube-state-metrics.fullname" $ }} + namespace: {{ . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role +{{- if (not $.Values.rbac.useExistingRole) }} + name: {{ template "kube-state-metrics.fullname" $ }} +{{- else }} + name: {{ $.Values.rbac.useExistingRole }} +{{- end }} +subjects: +- kind: ServiceAccount + name: {{ template "kube-state-metrics.serviceAccountName" $ }} + namespace: {{ template "kube-state-metrics.namespace" $ }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/service.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/service.yaml new file mode 100644 index 000000000..6c486a662 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/service.yaml @@ -0,0 +1,49 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + annotations: + {{- if .Values.prometheusScrape }} + prometheus.io/scrape: '{{ .Values.prometheusScrape }}' + {{- end }} + {{- if .Values.service.annotations }} + {{- toYaml .Values.service.annotations | nindent 4 }} + {{- end }} +spec: + type: "{{ .Values.service.type }}" + ports: + - name: "http" + protocol: TCP + port: {{ .Values.service.port | default 8080}} + {{- if .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + targetPort: {{ .Values.service.port | default 8080}} + {{ if .Values.selfMonitor.enabled }} + - name: "metrics" + protocol: TCP + port: {{ .Values.selfMonitor.telemetryPort | default 8081 }} + targetPort: {{ .Values.selfMonitor.telemetryPort | default 8081 }} + {{- if .Values.selfMonitor.telemetryNodePort }} + nodePort: {{ .Values.selfMonitor.telemetryNodePort }} + {{- end }} + {{ end }} +{{- if .Values.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.service.loadBalancerIP }}" +{{- end }} +{{- if .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.service.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} +{{- end }} +{{- if .Values.autosharding.enabled }} + clusterIP: None +{{- else if .Values.service.clusterIP }} + clusterIP: "{{ .Values.service.clusterIP }}" +{{- end }} + selector: + {{- include "kube-state-metrics.selectorLabels" . | indent 4 }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/serviceaccount.yaml new file mode 100644 index 000000000..a7ff4dd3d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: {{ template "kube-state-metrics.serviceAccountName" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- if .Values.serviceAccount.annotations }} + annotations: +{{ toYaml .Values.serviceAccount.annotations | indent 4 }} +{{- end }} +imagePullSecrets: + {{- include "kube-state-metrics.imagePullSecrets" (dict "Values" .Values "imagePullSecrets" .Values.serviceAccount.imagePullSecrets) | indent 2 }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/servicemonitor.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/servicemonitor.yaml new file mode 100644 index 000000000..79a07a655 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/servicemonitor.yaml @@ -0,0 +1,114 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + {{- with .Values.prometheus.monitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.prometheus.monitor.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ default "app.kubernetes.io/name" .Values.prometheus.monitor.jobLabel }} + {{- with .Values.prometheus.monitor.targetLabels }} + targetLabels: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + {{- with .Values.prometheus.monitor.podTargetLabels }} + podTargetLabels: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + {{- include "servicemonitor.scrapeLimits" .Values.prometheus.monitor | indent 2 }} + {{- if .Values.prometheus.monitor.namespaceSelector }} + namespaceSelector: + matchNames: + {{- with .Values.prometheus.monitor.namespaceSelector }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} + selector: + matchLabels: + {{- with .Values.prometheus.monitor.selectorOverride }} + {{- toYaml . | nindent 6 }} + {{- else }} + {{- include "kube-state-metrics.selectorLabels" . | indent 6 }} + {{- end }} + endpoints: + - port: http + {{- if .Values.prometheus.monitor.interval }} + interval: {{ .Values.prometheus.monitor.interval }} + {{- end }} + {{- if .Values.prometheus.monitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.prometheus.monitor.scrapeTimeout }} + {{- end }} + {{- if .Values.prometheus.monitor.proxyUrl }} + proxyUrl: {{ .Values.prometheus.monitor.proxyUrl}} + {{- end }} + {{- if .Values.prometheus.monitor.honorLabels }} + honorLabels: true + {{- end }} + {{- if .Values.prometheus.monitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.prometheus.monitor.metricRelabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.monitor.relabelings }} + relabelings: + {{- toYaml .Values.prometheus.monitor.relabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.monitor.scheme }} + scheme: {{ .Values.prometheus.monitor.scheme }} + {{- end }} + {{- if .Values.prometheus.monitor.tlsConfig }} + tlsConfig: + {{- toYaml .Values.prometheus.monitor.tlsConfig | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.monitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.prometheus.monitor.bearerTokenFile }} + {{- end }} + {{- with .Values.prometheus.monitor.bearerTokenSecret }} + bearerTokenSecret: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.selfMonitor.enabled }} + - port: metrics + {{- if .Values.prometheus.monitor.interval }} + interval: {{ .Values.prometheus.monitor.interval }} + {{- end }} + {{- if .Values.prometheus.monitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.prometheus.monitor.scrapeTimeout }} + {{- end }} + {{- if .Values.prometheus.monitor.proxyUrl }} + proxyUrl: {{ .Values.prometheus.monitor.proxyUrl}} + {{- end }} + {{- if .Values.prometheus.monitor.honorLabels }} + honorLabels: true + {{- end }} + {{- if .Values.prometheus.monitor.metricRelabelings }} + metricRelabelings: + {{- toYaml .Values.prometheus.monitor.metricRelabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.monitor.relabelings }} + relabelings: + {{- toYaml .Values.prometheus.monitor.relabelings | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.monitor.scheme }} + scheme: {{ .Values.prometheus.monitor.scheme }} + {{- end }} + {{- if .Values.prometheus.monitor.tlsConfig }} + tlsConfig: + {{- toYaml .Values.prometheus.monitor.tlsConfig | nindent 8 }} + {{- end }} + {{- if .Values.prometheus.monitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.prometheus.monitor.bearerTokenFile }} + {{- end }} + {{- with .Values.prometheus.monitor.bearerTokenSecret }} + bearerTokenSecret: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/stsdiscovery-role.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/stsdiscovery-role.yaml new file mode 100644 index 000000000..489de147c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/stsdiscovery-role.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.autosharding.enabled .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get +- apiGroups: + - apps + resourceNames: + - {{ template "kube-state-metrics.fullname" . }} + resources: + - statefulsets + verbs: + - get + - list + - watch +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml new file mode 100644 index 000000000..73b37a4f6 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.autosharding.enabled .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "kube-state-metrics.serviceAccountName" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml new file mode 100644 index 000000000..f46305b51 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml @@ -0,0 +1,44 @@ +{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1") (.Values.verticalPodAutoscaler.enabled) }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +spec: + {{- with .Values.verticalPodAutoscaler.recommenders }} + recommenders: + {{- toYaml . | nindent 4 }} + {{- end }} + resourcePolicy: + containerPolicies: + - containerName: {{ template "kube-state-metrics.name" . }} + {{- with .Values.verticalPodAutoscaler.controlledResources }} + controlledResources: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.verticalPodAutoscaler.controlledValues }} + controlledValues: {{ .Values.verticalPodAutoscaler.controlledValues }} + {{- end }} + {{- if .Values.verticalPodAutoscaler.maxAllowed }} + maxAllowed: + {{ toYaml .Values.verticalPodAutoscaler.maxAllowed | nindent 8 }} + {{- end }} + {{- if .Values.verticalPodAutoscaler.minAllowed }} + minAllowed: + {{ toYaml .Values.verticalPodAutoscaler.minAllowed | nindent 8 }} + {{- end }} + targetRef: + apiVersion: apps/v1 + {{- if .Values.autosharding.enabled }} + kind: StatefulSet + {{- else }} + kind: Deployment + {{- end }} + name: {{ template "kube-state-metrics.fullname" . }} + {{- with .Values.verticalPodAutoscaler.updatePolicy }} + updatePolicy: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/values.yaml new file mode 100644 index 000000000..00eabab6a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/kube-state-metrics/values.yaml @@ -0,0 +1,441 @@ +# Default values for kube-state-metrics. +prometheusScrape: true +image: + registry: registry.k8s.io + repository: kube-state-metrics/kube-state-metrics + # If unset use v + .Charts.appVersion + tag: "" + sha: "" + pullPolicy: IfNotPresent + +imagePullSecrets: [] +# - name: "image-pull-secret" + +global: + # To help compatibility with other charts which use global.imagePullSecrets. + # Allow either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style). + # global: + # imagePullSecrets: + # - name: pullSecret1 + # - name: pullSecret2 + # or + # global: + # imagePullSecrets: + # - pullSecret1 + # - pullSecret2 + imagePullSecrets: [] + # + # Allow parent charts to override registry hostname + imageRegistry: "" + +# If set to true, this will deploy kube-state-metrics as a StatefulSet and the data +# will be automatically sharded across <.Values.replicas> pods using the built-in +# autodiscovery feature: https://github.com/kubernetes/kube-state-metrics#automated-sharding +# This is an experimental feature and there are no stability guarantees. +autosharding: + enabled: false + +replicas: 1 + +# Number of old history to retain to allow rollback +# Default Kubernetes value is set to 10 +revisionHistoryLimit: 10 + +# List of additional cli arguments to configure kube-state-metrics +# for example: --enable-gzip-encoding, --log-file, etc. +# all the possible args can be found here: https://github.com/kubernetes/kube-state-metrics/blob/master/docs/cli-arguments.md +extraArgs: [] + +service: + port: 8080 + # Default to clusterIP for backward compatibility + type: ClusterIP + nodePort: 0 + loadBalancerIP: "" + # Only allow access to the loadBalancerIP from these IPs + loadBalancerSourceRanges: [] + clusterIP: "" + annotations: {} + +## Additional labels to add to all resources +customLabels: {} + # app: kube-state-metrics + +## Override selector labels +selectorOverride: {} + +## set to true to add the release label so scraping of the servicemonitor with kube-prometheus-stack works out of the box +releaseLabel: false + +hostNetwork: false + +rbac: + # If true, create & use RBAC resources + create: true + + # Set to a rolename to use existing role - skipping role creating - but still doing serviceaccount and rolebinding to it, rolename set here. + # useExistingRole: your-existing-role + + # If set to false - Run without Cluteradmin privs needed - ONLY works if namespace is also set (if useExistingRole is set this name is used as ClusterRole or Role to bind to) + useClusterRole: true + + # Add permissions for CustomResources' apiGroups in Role/ClusterRole. Should be used in conjunction with Custom Resource State Metrics configuration + # Example: + # - apiGroups: ["monitoring.coreos.com"] + # resources: ["prometheuses"] + # verbs: ["list", "watch"] + extraRules: [] + +# Configure kube-rbac-proxy. When enabled, creates one kube-rbac-proxy container per exposed HTTP endpoint (metrics and telemetry if enabled). +# The requests are served through the same service but requests are then HTTPS. +kubeRBACProxy: + enabled: false + image: + registry: quay.io + repository: brancz/kube-rbac-proxy + tag: v0.14.0 + sha: "" + pullPolicy: IfNotPresent + + # List of additional cli arguments to configure kube-rbac-prxy + # for example: --tls-cipher-suites, --log-file, etc. + # all the possible args can be found here: https://github.com/brancz/kube-rbac-proxy#usage + extraArgs: [] + + ## Specify security settings for a Container + ## Allows overrides and additional options compared to (Pod) securityContext + ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + containerSecurityContext: {} + + 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: 64Mi + # requests: + # cpu: 10m + # memory: 32Mi + + ## volumeMounts enables mounting custom volumes in rbac-proxy containers + ## Useful for TLS certificates and keys + volumeMounts: [] + # - mountPath: /etc/tls + # name: kube-rbac-proxy-tls + # readOnly: true + +serviceAccount: + # Specifies whether a ServiceAccount should be created, require rbac true + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + name: + # Reference to one or more secrets to be used when pulling images + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + imagePullSecrets: [] + # ServiceAccount annotations. + # Use case: AWS EKS IAM roles for service accounts + # ref: https://docs.aws.amazon.com/eks/latest/userguide/specify-service-account-role.html + annotations: {} + +prometheus: + monitor: + enabled: false + annotations: {} + additionalLabels: {} + namespace: "" + namespaceSelector: [] + jobLabel: "" + targetLabels: [] + podTargetLabels: [] + interval: "" + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + scrapeTimeout: "" + proxyUrl: "" + selectorOverride: {} + honorLabels: false + metricRelabelings: [] + relabelings: [] + scheme: "" + ## File to read bearer token for scraping targets + bearerTokenFile: "" + ## Secret to mount to read bearer token for scraping targets. The secret needs + ## to be in the same namespace as the service monitor and accessible by the + ## Prometheus Operator + bearerTokenSecret: {} + # name: secret-name + # key: key-name + tlsConfig: {} + +## Specify if a Pod Security Policy for kube-state-metrics must be created +## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +podSecurityPolicy: + enabled: false + annotations: {} + ## Specify pod annotations + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#apparmor + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#sysctl + ## + # seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*' + # seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default' + # apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default' + + additionalVolumes: [] + +## Configure network policy for kube-state-metrics +networkPolicy: + enabled: false + # networkPolicy.flavor -- Flavor of the network policy to use. + # Can be: + # * kubernetes for networking.k8s.io/v1/NetworkPolicy + # * cilium for cilium.io/v2/CiliumNetworkPolicy + flavor: kubernetes + + ## Configure the cilium network policy kube-apiserver selector + # cilium: + # kubeApiServerSelector: + # - toEntities: + # - kube-apiserver + + # egress: + # - {} + # ingress: + # - {} + # podSelector: + # matchLabels: + # app.kubernetes.io/name: kube-state-metrics + +securityContext: + enabled: true + runAsGroup: 65534 + runAsUser: 65534 + fsGroup: 65534 + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + +## Specify security settings for a Container +## Allows overrides and additional options compared to (Pod) securityContext +## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container +containerSecurityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + +## Node labels for pod assignment +## Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +## Affinity settings for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ +affinity: {} + +## Tolerations for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +tolerations: [] + +## Topology spread constraints for pod assignment +## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ +topologySpreadConstraints: [] + +# Annotations to be added to the deployment/statefulset +annotations: {} + +# Annotations to be added to the pod +podAnnotations: {} + +## Assign a PriorityClassName to pods if set +# priorityClassName: "" + +# Ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ +podDisruptionBudget: {} + +# Comma-separated list of metrics to be exposed. +# This list comprises of exact metric names and/or regex patterns. +# The allowlist and denylist are mutually exclusive. +metricAllowlist: [] + +# Comma-separated list of metrics not to be enabled. +# This list comprises of exact metric names and/or regex patterns. +# The allowlist and denylist are mutually exclusive. +metricDenylist: [] + +# Comma-separated list of additional Kubernetes label keys that will be used in the resource's +# labels metric. By default the metric contains only name and namespace labels. +# To include additional labels, provide a list of resource names in their plural form and Kubernetes +# label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. +# A single '*' can be provided per resource instead to allow any labels, but that has +# severe performance implications (Example: '=pods=[*]'). +metricLabelsAllowlist: [] + # - namespaces=[k8s-label-1,k8s-label-n] + +# Comma-separated list of Kubernetes annotations keys that will be used in the resource' +# labels metric. By default the metric contains only name and namespace labels. +# To include additional annotations provide a list of resource names in their plural form and Kubernetes +# annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. +# A single '*' can be provided per resource instead to allow any annotations, but that has +# severe performance implications (Example: '=pods=[*]'). +metricAnnotationsAllowList: [] + # - pods=[k8s-annotation-1,k8s-annotation-n] + +# Available collectors for kube-state-metrics. +# By default, all available resources are enabled, comment out to disable. +collectors: + - certificatesigningrequests + - configmaps + - cronjobs + - daemonsets + - deployments + - endpoints + - horizontalpodautoscalers + - ingresses + - jobs + - leases + - limitranges + - mutatingwebhookconfigurations + - namespaces + - networkpolicies + - nodes + - persistentvolumeclaims + - persistentvolumes + - poddisruptionbudgets + - pods + - replicasets + - replicationcontrollers + - resourcequotas + - secrets + - services + - statefulsets + - storageclasses + - validatingwebhookconfigurations + - volumeattachments + +# Enabling kubeconfig will pass the --kubeconfig argument to the container +kubeconfig: + enabled: false + # base64 encoded kube-config file + secret: + +# Enabling support for customResourceState, will create a configMap including your config that will be read from kube-state-metrics +customResourceState: + enabled: false + # Add (Cluster)Role permissions to list/watch the customResources defined in the config to rbac.extraRules + config: {} + +# Enable only the release namespace for collecting resources. By default all namespaces are collected. +# If releaseNamespace and namespaces are both set a merged list will be collected. +releaseNamespace: false + +# Comma-separated list(string) or yaml list of namespaces to be enabled for collecting resources. By default all namespaces are collected. +namespaces: "" + +# Comma-separated list of namespaces not to be enabled. If namespaces and namespaces-denylist are both set, +# only namespaces that are excluded in namespaces-denylist will be used. +namespacesDenylist: "" + +## Override the deployment namespace +## +namespaceOverride: "" + +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: 64Mi + # requests: + # cpu: 10m + # memory: 32Mi + +## Provide a k8s version to define apiGroups for podSecurityPolicy Cluster Role. +## For example: kubeTargetVersionOverride: 1.14.9 +## +kubeTargetVersionOverride: "" + +# Enable self metrics configuration for service and Service Monitor +# Default values for telemetry configuration can be overridden +# If you set telemetryNodePort, you must also set service.type to NodePort +selfMonitor: + enabled: false + # telemetryHost: 0.0.0.0 + # telemetryPort: 8081 + # telemetryNodePort: 0 + +# Enable vertical pod autoscaler support for kube-state-metrics +verticalPodAutoscaler: + enabled: false + + # Recommender responsible for generating recommendation for the object. + # List should be empty (then the default recommender will generate the recommendation) + # or contain exactly one recommender. + # recommenders: [] + # - name: custom-recommender-performance + + # List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory + controlledResources: [] + # Specifies which resource values should be controlled: RequestsOnly or RequestsAndLimits. + # controlledValues: RequestsAndLimits + + # Define the max allowed resources for the pod + maxAllowed: {} + # cpu: 200m + # memory: 100Mi + # Define the min allowed resources for the pod + minAllowed: {} + # cpu: 200m + # memory: 100Mi + + # updatePolicy: + # Specifies minimal number of replicas which need to be alive for VPA Updater to attempt pod eviction + # minReplicas: 1 + # Specifies whether recommended updates are applied when a Pod is started and whether recommended updates + # are applied during the life of a Pod. Possible values are "Off", "Initial", "Recreate", and "Auto". + # updateMode: Auto + +# volumeMounts are used to add custom volume mounts to deployment. +# See example below +volumeMounts: [] +# - mountPath: /etc/config +# name: config-volume + +# volumes are used to add custom volumes to deployment +# See example below +volumes: [] +# - configMap: +# name: cm-for-volume +# name: config-volume + +# Extra manifests to deploy as an array +extraManifests: [] + # - apiVersion: v1 + # kind: ConfigMap + # metadata: + # labels: + # name: prometheus-extra + # data: + # extra-data: "value" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/.helmignore new file mode 100644 index 000000000..f62b5519e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/.helmignore @@ -0,0 +1 @@ +templates/admission-webhooks/job-patch/README.md diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/Chart.lock new file mode 100644 index 000000000..ccd9266c2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +digest: sha256:fa87cb007564a39a72739a3e850a91d6b03c0fc27a1115deac042b3ef77b4142 +generated: "2024-06-21T17:38:34.069969308Z" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/Chart.yaml new file mode 100644 index 000000000..170415002 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/Chart.yaml @@ -0,0 +1,35 @@ +apiVersion: v2 +appVersion: 0.19.0 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +description: A Helm chart to deploy the New Relic Infrastructure Kubernetes Operator. +home: https://hub.docker.com/r/newrelic/newrelic-infra-operator +icon: https://newrelic.com/themes/custom/curio/assets/mediakit/new_relic_logo_vertical.svg +keywords: +- infrastructure +- newrelic +- monitoring +maintainers: +- name: alvarocabanas + url: https://github.com/alvarocabanas +- name: carlossscastro + url: https://github.com/carlossscastro +- name: sigilioso + url: https://github.com/sigilioso +- name: gsanchezgavier + url: https://github.com/gsanchezgavier +- name: kang-makes + url: https://github.com/kang-makes +- name: marcsanmi + url: https://github.com/marcsanmi +- name: paologallinaharbur + url: https://github.com/paologallinaharbur +- name: roobre + url: https://github.com/roobre +name: newrelic-infra-operator +sources: +- https://github.com/newrelic/newrelic-infra-operator +- https://github.com/newrelic/newrelic-infra-operator/tree/main/charts/newrelic-infra-operator +version: 2.11.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/README.md new file mode 100644 index 000000000..05e8a8d48 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/README.md @@ -0,0 +1,114 @@ +# newrelic-infra-operator + +A Helm chart to deploy the New Relic Infrastructure Kubernetes Operator. + +**Homepage:** + +## Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add newrelic-infra-operator https://newrelic.github.io/newrelic-infra-operator +helm upgrade --install newrelic-infra-operator/newrelic-infra-operator -f your-custom-values.yaml +``` + +## Source Code + +* +* + +## Usage example + +Make sure you have [added the New Relic chart repository.](../../README.md#install) + +Then, to install this chart, run the following command: + +```sh +helm upgrade --install [release-name] newrelic-infra-operator/newrelic-infra-operator --set cluster=my_cluster_name --set licenseKey [your-license-key] +``` + +When installing on Fargate add as well `--set fargate=true` + +### Configure in which pods the sidecar should be injected + +Policies are available in order to configure in which pods the sidecar should be injected. +Each policy is evaluated independently and if at least one policy matches the operator will inject the sidecar. + +Policies are composed by `namespaceSelector` checking the labels of the Pod namespace, `podSelector` checking +the labels of the Pod and `namespace` checking the namespace name. Each of those, if specified, are ANDed. + +By default, the policies are configured in order to inject the sidecar in each pod belonging to a Fargate profile. + +> Moreover, it is possible to add the label `infra-operator.newrelic.com/disable-injection` to Pods to exclude injection +for a single Pod that otherwise would be selected by the policies. + +Please make sure to configure policies correctly to avoid injecting sidecar for pods running on EC2 nodes +already monitored by the infrastructure DaemonSet. + +### Configure the sidecar with labelsSelectors + +It is also possible to configure `resourceRequirements` and `extraEnvVars` based on the labels of the mutating Pod. + +The current configuration increases the resource requirements for sidecar injected on `KSM` instances. Moreover, +injectes disable the `DISABLE_KUBE_STATE_METRICS` environment variable for Pods not running on `KSM` instances +to decrease the load on the API server. + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| admissionWebhooksPatchJob | object | See `values.yaml` | Image used to create certificates and inject them to the admission webhook | +| admissionWebhooksPatchJob.image.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | +| admissionWebhooksPatchJob.volumeMounts | list | `[]` | Volume mounts to add to the job, you might want to mount tmp if Pod Security Policies. Enforce a read-only root. | +| admissionWebhooksPatchJob.volumes | list | `[]` | Volumes to add to the job container. | +| affinity | object | `{}` | Sets pod/node affinities. Can be configured also with `global.affinity` | +| certManager.enabled | bool | `false` | Use cert manager for webhook certs | +| cluster | string | `""` | Name of the Kubernetes cluster monitored. Mandatory. Can be configured also with `global.cluster` | +| config | object | See `values.yaml` | Operator configuration | +| config.ignoreMutationErrors | bool | `true` | IgnoreMutationErrors instruments the operator to ignore injection error instead of failing. If set to false errors of the injection could block the creation of pods. | +| config.infraAgentInjection | object | See `values.yaml` | configuration of the sidecar injection webhook | +| config.infraAgentInjection.agentConfig | object | See `values.yaml` | agentConfig contains the configuration for the container agent injected | +| config.infraAgentInjection.agentConfig.configSelectors | list | See `values.yaml` | configSelectors is the way to configure resource requirements and extra envVars of the injected sidecar container. When mutating it will be applied the first configuration having the labelSelector matching with the mutating pod. | +| config.infraAgentInjection.agentConfig.image | object | See `values.yaml` | Image of the infrastructure agent to be injected. | +| containerSecurityContext | object | `{}` | Sets security context (at container level). Can be configured also with `global.containerSecurityContext` | +| customSecretLicenseKey | string | `""` | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` | +| customSecretName | string | `""` | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` | +| dnsConfig | object | `{}` | Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` | +| fullnameOverride | string | `""` | Override the full name of the release | +| hostNetwork | bool | `false` | Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` | +| image | object | See `values.yaml` | Image for the New Relic Infrastructure Operator | +| image.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | +| licenseKey | string | `""` | This set this license key to use. Can be configured also with `global.licenseKey` | +| nameOverride | string | `""` | Override the name of the chart | +| nodeSelector | object | `{}` | Sets pod's node selector. Can be configured also with `global.nodeSelector` | +| podAnnotations | object | `{}` | Annotations to add to the pod. | +| podSecurityContext | object | `{"fsGroup":1001,"runAsGroup":1001,"runAsUser":1001}` | Sets security context (at pod level). Can be configured also with `global.podSecurityContext` | +| priorityClassName | string | `""` | Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` | +| rbac.pspEnabled | bool | `false` | Whether the chart should create Pod Security Policy objects. | +| replicas | int | `1` | | +| resources | object | `{"limits":{"memory":"80M"},"requests":{"cpu":"100m","memory":"30M"}}` | Resources available for this pod | +| serviceAccount | object | See `values.yaml` | Settings controlling ServiceAccount creation | +| serviceAccount.create | bool | `true` | Specifies whether a ServiceAccount should be created | +| timeoutSeconds | int | `10` | Webhook timeout Ref: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts | +| tolerations | list | `[]` | Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` | + +## Maintainers + +* [alvarocabanas](https://github.com/alvarocabanas) +* [carlossscastro](https://github.com/carlossscastro) +* [sigilioso](https://github.com/sigilioso) +* [gsanchezgavier](https://github.com/gsanchezgavier) +* [kang-makes](https://github.com/kang-makes) +* [marcsanmi](https://github.com/marcsanmi) +* [paologallinaharbur](https://github.com/paologallinaharbur) +* [roobre](https://github.com/roobre) diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/README.md.gotmpl new file mode 100644 index 000000000..1ef603355 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/README.md.gotmpl @@ -0,0 +1,77 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +## Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add newrelic-infra-operator https://newrelic.github.io/newrelic-infra-operator +helm upgrade --install newrelic-infra-operator/newrelic-infra-operator -f your-custom-values.yaml +``` + +{{ template "chart.sourcesSection" . }} + +## Usage example + +Make sure you have [added the New Relic chart repository.](../../README.md#install) + +Then, to install this chart, run the following command: + +```sh +helm upgrade --install [release-name] newrelic-infra-operator/newrelic-infra-operator --set cluster=my_cluster_name --set licenseKey [your-license-key] +``` + +When installing on Fargate add as well `--set fargate=true` + +### Configure in which pods the sidecar should be injected + +Policies are available in order to configure in which pods the sidecar should be injected. +Each policy is evaluated independently and if at least one policy matches the operator will inject the sidecar. + +Policies are composed by `namespaceSelector` checking the labels of the Pod namespace, `podSelector` checking +the labels of the Pod and `namespace` checking the namespace name. Each of those, if specified, are ANDed. + +By default, the policies are configured in order to inject the sidecar in each pod belonging to a Fargate profile. + +> Moreover, it is possible to add the label `infra-operator.newrelic.com/disable-injection` to Pods to exclude injection +for a single Pod that otherwise would be selected by the policies. + +Please make sure to configure policies correctly to avoid injecting sidecar for pods running on EC2 nodes +already monitored by the infrastructure DaemonSet. + +### Configure the sidecar with labelsSelectors + +It is also possible to configure `resourceRequirements` and `extraEnvVars` based on the labels of the mutating Pod. + +The current configuration increases the resource requirements for sidecar injected on `KSM` instances. Moreover, +injectes disable the `DISABLE_KUBE_STATE_METRICS` environment variable for Pods not running on `KSM` instances +to decrease the load on the API server. + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +{{ template "chart.valuesSection" . }} + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/Chart.yaml new file mode 100644 index 000000000..b65ac15d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +- name: kang-makes + url: https://github.com/kang-makes +name: common-library +type: library +version: 1.2.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/DEVELOPERS.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/DEVELOPERS.md new file mode 100644 index 000000000..3ccc108e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/DEVELOPERS.md @@ -0,0 +1,663 @@ +# Functions/templates documented for chart writers +Here is some rough documentation separated by the file that contains the function, the function +name and how to use it. We are not covering functions that start with `_` (e.g. +`newrelic.common.license._licenseKey`) because they are used internally by this library for +other helpers. Helm does not have the concept of "public" or "private" functions/templates so +this is a convention of ours. + +## _naming.tpl +These functions are used to name objects. + +### `newrelic.common.naming.name` +This is the same as the idiomatic `CHART-NAME.name` that is created when you use `helm create`. + +It honors `.Values.nameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.name" . }} +``` + +### `newrelic.common.naming.fullname` +This is the same as the idiomatic `CHART-NAME.fullname` that is created when you use `helm create` + +It honors `.Values.fullnameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.fullname" . }} +``` + +### `newrelic.common.naming.chart` +This is the same as the idiomatic `CHART-NAME.chart` that is created when you use `helm create`. + +It is mostly useless for chart writers. It is used internally for templating the labels but there +is no reason to keep it "private". + +Usage: +```mustache +{{ include "newrelic.common.naming.chart" . }} +``` + +### `newrelic.common.naming.truncateToDNS` +This is a useful template that could be used to trim a string to 63 chars and does not end with a dash (`-`). +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $truncatedName := include "newrelic.common.naming.truncateToDNS" $nameToTruncate }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-string-that-should-be */ -}} +``` + +### `newrelic.common.naming.truncateToDNSWithSuffix` +This template function is the same as the above but instead of receiving a string you should give a `dict` +with a `name` and a `suffix`. This function will join them with a dash (`-`) and trim the `name` so the +result of `name-suffix` is no more than 63 chars + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $suffix := "A-NOT-SO-LONG-SUFFIX" }} +{{- $truncatedName := include "truncateToDNSWithSuffix" (dict "name" $nameToTruncate "suffix" $suffix) }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-A-NOT-SO-LONG-SUFFIX */ -}} +``` + + + +## _labels.tpl +### `newrelic.common.labels`, `newrelic.common.labels.selectorLabels` and `newrelic.common.labels.podLabels` +These are functions that are used to label objects. They are configured by this `values.yaml` +```yaml +global: + podLabels: {} # included in all the pods of all the charts that implement this library + labels: {} # included in all the objects of all the charts that implement this library +podLabels: {} # included in all the pods of this chart +labels: {} # included in all the objects of this chart +``` + +label maps are merged from global to local values. + +And chart writer should use them like this: +```mustache +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} +``` + +`newrelic.common.labels.podLabels` includes `newrelic.common.labels.selectorLabels` automatically. + + + +## _priority-class-name.tpl +### `newrelic.common.priorityClassName` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + priorityClassName: "" +priorityClassName: "" +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `priorityClassName` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} +``` + + + +## _hostnetwork.tpl +### `newrelic.common.hostNetwork` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + hostNetwork: # Note that this is empty (nil) +hostNetwork: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `hostNetwork` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.hostNetwork" . }} + hostNetwork: {{ . }} + {{- end }} +``` + +### `newrelic.common.hostNetwork.value` +This function is an abstraction of the function above but this returns directly "true" or "false". + +Be careful with using this with an `if` as Helm does evaluate "false" (string) as `true`. + +Usage (example in a pod spec): +```mustache +spec: + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} +``` + + + +## _dnsconfig.tpl +### `newrelic.common.dnsConfig` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + dnsConfig: {} +dnsConfig: {} +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `dnsConfig` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _images.tpl +These functions help us to deal with how images are templated. This allows setting `registries` +where to fetch images globally while being flexible enough to fit in different maps of images +and deployments with one or more images. This is the example of a complex `values.yaml` that +we are going to use during the documentation of these functions: + +```yaml +global: + images: + registry: nexus-3-instance.internal.clients-domain.tld +jobImage: + registry: # defaults to "example.tld" when empty in these examples + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent + pullSecrets: [] +images: + integration: + registry: + repository: newrelic/nri-kube-events + tag: 1.8.0 + pullPolicy: IfNotPresent + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.22.0 + pullPolicy: IfNotPresent + pullSecrets: [] +``` + +### `newrelic.common.images.image` +This will return a string with the image ready to be downloaded that includes the registry, the image and the tag. +`defaultRegistry` is used to keep `registry` field empty in `values.yaml` so you can override the image using +`global.images.registry`, your local `jobImage.registry` and be able to fallback to a registry that is not `docker.io` +(Or the default repository that the client could have set in the CRI). + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.image" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.registry` +It returns the registry from the global or local values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.registry" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.repository` +It returns the image from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.tag` +It returns the image's tag from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.renderPullSecrets` +If returns a merged map that contains the pull secrets from the global configuration and the local one. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.jobImage.pullSecrets "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +``` + + + +## _serviceaccount.tpl +These functions are used to evaluate if the service account should be created, with which name and add annotations to it. + +The functions that the common library has implemented for service accounts are: +* `newrelic.common.serviceAccount.create` +* `newrelic.common.serviceAccount.name` +* `newrelic.common.serviceAccount.annotations` + +Usage: +```mustache +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +``` + + + +## _affinity.tpl, _nodeselector.tpl and _tolerations.tpl +These three files are almost the same and they follow the idiomatic way of `helm create`. + +Each function also looks if there is a global value like the other helpers. +```yaml +global: + affinity: {} + nodeSelector: {} + tolerations: [] +affinity: {} +nodeSelector: {} +tolerations: [] +``` + +The values here are replaced instead of be merged. If a value at root level is found, the global one is ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _agent-config.tpl +### `newrelic.common.agentConfig.defaults` +This returns a YAML that the agent can use directly as a config that includes other options from the values file like verbose mode, +custom attributes, FedRAMP and such. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include newrelic.common.naming.truncateToDNSWithSuffix (dict "name" (include "newrelic.common.naming.fullname" .) suffix "agent-config") }} + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "newrelic.common.agentConfig.defaults" . | nindent 4 }} +``` + + + +## _cluster.tpl +### `newrelic.common.cluster` +Returns the cluster name + +Usage: +```mustache +{{ include "newrelic.common.cluster" . }} +``` + + + +## _custom-attributes.tpl +### `newrelic.common.customAttributes` +Return custom attributes in YAML format. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + name: example +data: + custom-attributes.yaml: | + {{- include "newrelic.common.customAttributes" . | nindent 4 }} + custom-attributes.json: | + {{- include "newrelic.common.customAttributes" . | fromYaml | toJson | nindent 4 }} +``` + + + +## _fedramp.tpl +### `newrelic.common.fedramp.enabled` +Returns true if FedRAMP is enabled or an empty string if not. It can be safely used in conditionals as an empty string is a Helm falsiness. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled" . }} +``` + +### `newrelic.common.fedramp.enabled.value` +Returns true if FedRAMP is enabled or false if not. This is to have the value of FedRAMP ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled.value" . }} +``` + + + +## _license.tpl +### `newrelic.common.license.secretName` and ### `newrelic.common.license.secretKeyName` +Returns the secret and key inside the secret where to read the license key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the license key. + +To create the secret use `newrelic.common.license.secret`. + +Usage: +```mustache +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + containers: + - name: agent + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} +``` + + + +## _license_secret.tpl +### `newrelic.common.license.secret` +This function templates the secret that is used by agents and integrations with the license Key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any license key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.license.secret" . -}} +``` + + + +## _insights.tpl +### `newrelic.common.insightsKey.secretName` and ### `newrelic.common.insightsKey.secretKeyName` +Returns the secret and key inside the secret where to read the insights key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the insights key. + +To create the secret use `newrelic.common.insightsKey.secret`. + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: statsd +spec: + containers: + - name: statsd + env: + - name: "INSIGHTS_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + key: {{ include "newrelic.common.insightsKey.secretKeyName" . }} +``` + + + +## _insights_secret.tpl +### `newrelic.common.insightsKey.secret` +This function templates the secret that is used by agents and integrations with the insights key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any insights key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.insightsKey.secret" . -}} +``` + + + +## _low-data-mode.tpl +### `newrelic.common.lowDataMode` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + lowDataMode: # Note that this is empty (nil) +lowDataMode: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `lowdataMode` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.lowDataMode" . }} +``` + + + +## _privileged.tpl +### `newrelic.common.privileged` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + privileged: # Note that this is empty (nil) +privileged: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `privileged` is defined, the global one is going to be always ignored. + +Chart writers could override this and put directly a `true` in the `values.yaml` to override the +default of the common library. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.privileged" . }} +``` + +### `newrelic.common.privileged.value` +Returns true if privileged mode is enabled or false if not. This is to have the value of privileged ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.privileged.value" . }} +``` + + + +## _proxy.tpl +### `newrelic.common.proxy` +Returns the proxy URL configured by the user. + +Usage: +```mustache +{{ include "newrelic.common.proxy" . }} +``` + + + +## _security-context.tpl +Use these functions to share the security context among all charts. Useful in clusters that have security enforcing not to +use the root user (like OpenShift) or users that have an admission webhooks. + +The functions are: +* `newrelic.common.securityContext.container` +* `newrelic.common.securityContext.pod` + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + spec: + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + containers: + - name: example + {{- with include "nriKubernetes.securityContext.container" . }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} +``` + + + +## _staging.tpl +### `newrelic.common.nrStaging` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + nrStaging: # Note that this is empty (nil) +nrStaging: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `nrStaging` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging" . }} +``` + +### `newrelic.common.nrStaging.value` +Returns true if staging is enabled or false if not. This is to have the staging value ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging.value" . }} +``` + + + +## _verbose-log.tpl +### `newrelic.common.verboseLog` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + verboseLog: # Note that this is empty (nil) +verboseLog: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `verboseLog` is defined, the global one is going to be always ignored. + +Usage: +```mustache +{{ include "newrelic.common.verboseLog" . }} +``` + +### `newrelic.common.verboseLog.valueAsBoolean` +Returns true if verbose is enabled or false if not. This is to have the verbose value ready to be templated as a boolean + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsBoolean" . }} +``` + +### `newrelic.common.verboseLog.valueAsInt` +Returns 1 if verbose is enabled or 0 if not. This is to have the verbose value ready to be templated as an integer + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsInt" . }} +``` diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/README.md new file mode 100644 index 000000000..10f08ca67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/README.md @@ -0,0 +1,106 @@ +# Helm Common library + +The common library is a way to unify the UX through all the Helm charts that implement it. + +The tooling suite that New Relic is huge and growing and this allows to set things globally +and locally for a single chart. + +## Documentation for chart writers + +If you are writing a chart that is going to use this library you can check the [developers guide](/library/common-library/DEVELOPERS.md) to see all +the functions/templates that we have implemented, what they do and how to use them. + +## Values managed globally + +We want to have a seamless experience through all the charts so we created this library that tries to standardize the behaviour +of all the charts. Sadly, because of the complexity of all these integrations, not all the charts behave exactly as expected. + +An example is `newrelic-infrastructure` that ignores `hostNetwork` in the control plane scraper because most of the users has the +control plane listening in the node to `localhost`. + +For each chart that has a special behavior (or further information of the behavior) there is a "chart particularities" section +in its README.md that explains which is the expected behavior. + +At the time of writing this, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this +library and honors global options as described in this document. + +Here is a list of global options: + +| Global keys | Local keys | Default | Merged[1](#values-managed-globally-1) | Description | +|-------------|------------|---------|--------------------------------------------------|-------------| +| global.cluster | cluster | `""` | | Name of the Kubernetes cluster monitored | +| global.licenseKey | licenseKey | `""` | | This set this license key to use | +| global.customSecretName | customSecretName | `""` | | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there | +| global.customSecretLicenseKey | customSecretLicenseKey | `""` | | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located | +| global.podLabels | podLabels | `{}` | yes | Additional labels for chart pods | +| global.labels | labels | `{}` | yes | Additional labels for chart objects | +| global.priorityClassName | priorityClassName | `""` | | Sets pod's priorityClassName | +| global.hostNetwork | hostNetwork | `false` | | Sets pod's hostNetwork | +| global.dnsConfig | dnsConfig | `{}` | | Sets pod's dnsConfig | +| global.images.registry | See [Further information](#values-managed-globally-2) | `""` | | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.images.pullSecrets | See [Further information](#values-managed-globally-2) | `[]` | yes | Set secrets to be able to fetch images | +| global.podSecurityContext | podSecurityContext | `{}` | | Sets security context (at pod level) | +| global.containerSecurityContext | containerSecurityContext | `{}` | | Sets security context (at container level) | +| global.affinity | affinity | `{}` | | Sets pod/node affinities | +| global.nodeSelector | nodeSelector | `{}` | | Sets pod's node selector | +| global.tolerations | tolerations | `[]` | | Sets pod's tolerations to node taints | +| global.serviceAccount.create | serviceAccount.create | `true` | | Configures if the service account should be created or not | +| global.serviceAccount.name | serviceAccount.name | name of the release | | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. | +| global.serviceAccount.annotations | serviceAccount.annotations | `{}` | yes | Add these annotations to the service account we create | +| global.customAttributes | customAttributes | `{}` | | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.fedramp | fedramp | `false` | | Enables FedRAMP | +| global.lowDataMode | lowDataMode | `false` | | Reduces number of metrics sent in order to reduce costs | +| global.privileged | privileged | Depends on the chart | | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | +| global.proxy | proxy | `""` | | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.nrStaging | nrStaging | `false` | | Send the metrics to the staging backend. Requires a valid staging license key | +| global.verboseLog | verboseLog | `false` | | Sets the debug/trace logs to this integration or all integrations if it is set globally | + +### Further information + +#### 1. Merged + +Merged means that the values from global are not replaced by the local ones. Think in this example: +```yaml +global: + labels: + global: global + hostNetwork: true + nodeSelector: + global: global + +labels: + local: local +nodeSelector: + local: local +hostNetwork: false +``` + +This values will template `hostNetwork` to `false`, a map of labels `{ "global": "global", "local": "local" }` and a `nodeSelector` with +`{ "local": "local" }`. + +As Helm by default merges all the maps it could be confusing that we have two behaviors (merging `labels` and replacing `nodeSelector`) +the `values` from global to local. This is the rationale behind this: +* `hostNetwork` is templated to `false` because is overriding the value defined globally. +* `labels` are merged because the user may want to label all the New Relic pods at once and label other solution pods differently for + clarity' sake. +* `nodeSelector` does not merge as `labels` because could make it harder to overwrite/delete a selector that comes from global because + of the logic that Helm follows merging maps. + + +#### 2. Fine grain registries + +Some charts only have 1 image while others that can have 2 or more images. The local path for the registry can change depending +on the chart itself. + +As this is mostly unique per helm chart, you should take a look to the chart's values table (or directly to the `values.yaml` file to see all the +images that you can change. + +This should only be needed if you have an advanced setup that forces you to have granularity enough to force a proxy/cache registry per integration. + + + +#### 3. Privileged mode + +By default, from the common library, the privileged mode is set to false. But most of the helm charts require this to be true to fetch more +metrics so could see a true in some charts. The consequences of the privileged mode differ from one chart to another so for each chart that +honors the privileged mode toggle should be a section in the README explaining which is the behavior with it enabled or disabled. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_affinity.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_affinity.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod affinity */ -}} +{{- define "newrelic.common.affinity" -}} + {{- if .Values.affinity -}} + {{- toYaml .Values.affinity -}} + {{- else if .Values.global -}} + {{- if .Values.global.affinity -}} + {{- toYaml .Values.global.affinity -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_agent-config.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..9c32861a0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,26 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +log: + level: trace +{{- end }} + +{{- if (include "newrelic.common.nrStaging" . ) }} +staging: true +{{- end }} + +{{- with include "newrelic.common.proxy" . }} +proxy: {{ . | quote }} +{{- end }} + +{{- with include "newrelic.common.fedramp.enabled" . }} +fedramp: {{ . }} +{{- end }} + +{{- with fromYaml ( include "newrelic.common.customAttributes" . ) }} +custom_attributes: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_cluster.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_cluster.tpl @@ -0,0 +1,15 @@ +{{/* +Return the cluster +*/}} +{{- define "newrelic.common.cluster" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.cluster -}} + {{- .Values.cluster -}} +{{- else if $global.cluster -}} + {{- $global.cluster -}} +{{- else -}} + {{ fail "There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required." }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_custom-attributes.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_custom-attributes.tpl @@ -0,0 +1,17 @@ +{{/* +This will render custom attributes as a YAML ready to be templated or be used with `fromYaml`. +*/}} +{{- define "newrelic.common.customAttributes" -}} +{{- $customAttributes := dict -}} + +{{- $global := index .Values "global" | default dict -}} +{{- if $global.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes $global.customAttributes -}} +{{- end -}} + +{{- if .Values.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes .Values.customAttributes -}} +{{- end -}} + +{{- toYaml $customAttributes -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_dnsconfig.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_dnsconfig.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod dnsConfig */ -}} +{{- define "newrelic.common.dnsConfig" -}} + {{- if .Values.dnsConfig -}} + {{- toYaml .Values.dnsConfig -}} + {{- else if .Values.global -}} + {{- if .Values.global.dnsConfig -}} + {{- toYaml .Values.global.dnsConfig -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_fedramp.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_fedramp.tpl @@ -0,0 +1,25 @@ +{{- /* Defines the fedRAMP flag */ -}} +{{- define "newrelic.common.fedramp.enabled" -}} + {{- if .Values.fedramp -}} + {{- if .Values.fedramp.enabled -}} + {{- .Values.fedramp.enabled -}} + {{- end -}} + {{- else if .Values.global -}} + {{- if .Values.global.fedramp -}} + {{- if .Values.global.fedramp.enabled -}} + {{- .Values.global.fedramp.enabled -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{- /* Return FedRAMP value directly ready to be templated */ -}} +{{- define "newrelic.common.fedramp.enabled.value" -}} +{{- if include "newrelic.common.fedramp.enabled" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_hostnetwork.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_hostnetwork.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the hostNetwork toggle. +This helper allows to override the global `.global.hostNetwork` with the value of `.hostNetwork`. +Returns "true" if `hostNetwork` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.hostNetwork" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- /* +`get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs + +We also want only to return when this is true, returning `false` here will template "false" (string) when doing +an `(include "newrelic.common.hostNetwork" .)`, which is not an "empty string" so it is `true` if it is used +as an evaluation somewhere else. +*/ -}} +{{- if get .Values "hostNetwork" | kindIs "bool" -}} + {{- if .Values.hostNetwork -}} + {{- .Values.hostNetwork -}} + {{- end -}} +{{- else if get $global "hostNetwork" | kindIs "bool" -}} + {{- if $global.hostNetwork -}} + {{- $global.hostNetwork -}} + {{- end -}} +{{- end -}} +{{- end -}} + + +{{- /* +Abstraction of the hostNetwork toggle. +This helper abstracts the function "newrelic.common.hostNetwork" to return true or false directly. +*/ -}} +{{- define "newrelic.common.hostNetwork.value" -}} +{{- if include "newrelic.common.hostNetwork" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_images.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..d4fb43290 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_images.tpl @@ -0,0 +1,94 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "defaultRegistry" .defaultRegistry "context" .context ) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic.common.images.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image registry +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} +{{- $globalRegistry := "" -}} +{{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- with .context.Values.global.images.registry -}} + {{- $globalRegistry = . -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- $localRegistry := "" -}} +{{- if .imageRoot.registry -}} + {{- $localRegistry = .imageRoot.registry -}} +{{- end -}} + +{{- $registry := $localRegistry | default $globalRegistry | default .defaultRegistry -}} +{{- if $registry -}} + {{- $registry -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image repository +{{ include "newrelic.common.images.repository" .Values.path.to.the.image }} +*/ -}} +{{- define "newrelic.common.images.repository" -}} + {{- .repository -}} +{{- end -}} + + + +{{- /* +Return the proper image tag +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.tag" -}} + {{- .imageRoot.tag | default .context.Chart.AppVersion | toString -}} +{{- end -}} + + + +{{- /* +Return the proper Image Pull Registry Secret Names evaluating values as templates +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.path.to.the.images.pullSecrets1, .Values.path.to.the.images.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- if .context.Values.global.images.pullSecrets -}} + {{- range .context.Values.global.images.pullSecrets -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- range .pullSecrets -}} + {{- if not (empty .) -}} + {{- range . -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if $flatlist -}} + {{- toYaml $flatlist -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_insights.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_insights.tpl new file mode 100644 index 000000000..895c37732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_insights.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the Insights Key. +*/}} +{{- define "newrelic.common.insightsKey.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "insightskey" ) -}} +{{- include "newrelic.common.insightsKey._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +*/}} +{{- define "newrelic.common.insightsKey.secretKeyName" -}} +{{- include "newrelic.common.insightsKey._customSecretKey" . | default "insightsKey" -}} +{{- end -}} + +{{/* +Return local insightsKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._licenseKey" -}} +{{- if .Values.insightsKey -}} + {{- .Values.insightsKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.insightsKey -}} + {{- .Values.global.insightsKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the Insights Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretName" -}} +{{- if .Values.customInsightsKeySecretName -}} + {{- .Values.customInsightsKeySecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretName -}} + {{- .Values.global.customInsightsKeySecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretKey" -}} +{{- if .Values.customInsightsKeySecretKey -}} + {{- .Values.customInsightsKeySecretKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretKey }} + {{- .Values.global.customInsightsKeySecretKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_insights_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_insights_secret.yaml.tpl new file mode 100644 index 000000000..556caa6ca --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_insights_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the insights key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.insightsKey.secret" }} +{{- if not (include "newrelic.common.insightsKey._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.insightsKey._licenseKey" .) }} + {{- fail "You must specify a insightsKey or a customInsightsSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.insightsKey.secretKeyName" . }}: {{ include "newrelic.common.insightsKey._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_labels.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_labels.tpl @@ -0,0 +1,54 @@ +{{/* +This will render the labels that should be used in all the manifests used by the helm chart. +*/}} +{{- define "newrelic.common.labels" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- $chart := dict "helm.sh/chart" (include "newrelic.common.naming.chart" . ) -}} +{{- $managedBy := dict "app.kubernetes.io/managed-by" .Release.Service -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $labels := mustMergeOverwrite $chart $managedBy $selectorLabels -}} +{{- if .Chart.AppVersion -}} +{{- $labels = mustMergeOverwrite $labels (dict "app.kubernetes.io/version" .Chart.AppVersion) -}} +{{- end -}} + +{{- $globalUserLabels := $global.labels | default dict -}} +{{- $localUserLabels := .Values.labels | default dict -}} + +{{- $labels = mustMergeOverwrite $labels $globalUserLabels $localUserLabels -}} + +{{- toYaml $labels -}} +{{- end -}} + + + +{{/* +This will render the labels that should be used in deployments/daemonsets template pods as a selector. +*/}} +{{- define "newrelic.common.labels.selectorLabels" -}} +{{- $name := dict "app.kubernetes.io/name" ( include "newrelic.common.naming.name" . ) -}} +{{- $instance := dict "app.kubernetes.io/instance" .Release.Name -}} + +{{- $selectorLabels := mustMergeOverwrite $name $instance -}} + +{{- toYaml $selectorLabels -}} +{{- end }} + + + +{{/* +Pod labels +*/}} +{{- define "newrelic.common.labels.podLabels" -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $global := index .Values "global" | default dict -}} +{{- $globalPodLabels := $global.podLabels | default dict }} + +{{- $localPodLabels := .Values.podLabels | default dict }} + +{{- $podLabels := mustMergeOverwrite $selectorLabels $globalPodLabels $localPodLabels -}} + +{{- toYaml $podLabels -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_license.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..647b4ff43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_license.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "license" ) -}} +{{- include "newrelic.common.license._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +*/}} +{{- define "newrelic.common.license.secretKeyName" -}} +{{- include "newrelic.common.license._customSecretKey" . | default "licenseKey" -}} +{{- end -}} + +{{/* +Return local licenseKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._licenseKey" -}} +{{- if .Values.licenseKey -}} + {{- .Values.licenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.licenseKey -}} + {{- .Values.global.licenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the License Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretName" -}} +{{- if .Values.customSecretName -}} + {{- .Values.customSecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretName -}} + {{- .Values.global.customSecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretKey" -}} +{{- if .Values.customSecretLicenseKey -}} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_license_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_license_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the license key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.license.secret" }} +{{- if not (include "newrelic.common.license._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.license._licenseKey" .) }} + {{- fail "You must specify a licenseKey or a customSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.license.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.license.secretKeyName" . }}: {{ include "newrelic.common.license._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_low-data-mode.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_low-data-mode.tpl @@ -0,0 +1,26 @@ +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..19fa92648 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_naming.tpl @@ -0,0 +1,73 @@ +{{/* +This is an function to be called directly with a string just to truncate strings to +63 chars because some Kubernetes name fields are limited to that. +*/}} +{{- define "newrelic.common.naming.truncateToDNS" -}} +{{- . | trunc 63 | trimSuffix "-" }} +{{- end }} + + + +{{- /* +Given a name and a suffix returns a 'DNS Valid' which always include the suffix, truncating the name if needed. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If suffix is too long it gets truncated but it always takes precedence over name, so a 63 chars suffix would suppress the name. +Usage: +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "" "suffix" "my-suffix" ) }} +*/ -}} +{{- define "newrelic.common.naming.truncateToDNSWithSuffix" -}} +{{- $suffix := (include "newrelic.common.naming.truncateToDNS" .suffix) -}} +{{- $maxLen := (max (sub 63 (add1 (len $suffix))) 0) -}} {{- /* We prepend "-" to the suffix so an additional character is needed */ -}} + +{{- $newName := .name | trunc ($maxLen | int) | trimSuffix "-" -}} +{{- if $newName -}} +{{- printf "%s-%s" $newName $suffix -}} +{{- else -}} +{{ $suffix }} +{{- end -}} + +{{- end -}} + + + +{{/* +Expand the name of the chart. +Uses the Chart name by default if nameOverride is not set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.name" -}} +{{- $name := .Values.nameOverride | default .Chart.Name -}} +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end }} + + + +{{/* +Create a default fully qualified app name. +By default the full name will be "" just in if it has the chart name included in that, if not +it will be concatenated like "-". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.fullname" -}} +{{- $name := include "newrelic.common.naming.name" . -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} + +{{- end -}} + + + +{{/* +Create chart name and version as used by the chart label. +This function should not be used for naming objects. Use "common.naming.{name,fullname}" instead. +*/}} +{{- define "newrelic.common.naming.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_nodeselector.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_nodeselector.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod nodeSelector */ -}} +{{- define "newrelic.common.nodeSelector" -}} + {{- if .Values.nodeSelector -}} + {{- toYaml .Values.nodeSelector -}} + {{- else if .Values.global -}} + {{- if .Values.global.nodeSelector -}} + {{- toYaml .Values.global.nodeSelector -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_priority-class-name.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_priority-class-name.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the pod priorityClassName */ -}} +{{- define "newrelic.common.priorityClassName" -}} + {{- if .Values.priorityClassName -}} + {{- .Values.priorityClassName -}} + {{- else if .Values.global -}} + {{- if .Values.global.priorityClassName -}} + {{- .Values.global.priorityClassName -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_privileged.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_privileged.tpl @@ -0,0 +1,28 @@ +{{- /* +This is a helper that returns whether the chart should assume the user is fine deploying privileged pods. +*/ -}} +{{- define "newrelic.common.privileged" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists. */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values "privileged" | kindIs "bool" -}} + {{- if .Values.privileged -}} + {{- .Values.privileged -}} + {{- end -}} +{{- else if get $global "privileged" | kindIs "bool" -}} + {{- if $global.privileged -}} + {{- $global.privileged -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* Return directly "true" or "false" based in the exist of "newrelic.common.privileged" */ -}} +{{- define "newrelic.common.privileged.value" -}} +{{- if include "newrelic.common.privileged" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_proxy.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_proxy.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the proxy */ -}} +{{- define "newrelic.common.proxy" -}} + {{- if .Values.proxy -}} + {{- .Values.proxy -}} + {{- else if .Values.global -}} + {{- if .Values.global.proxy -}} + {{- .Values.global.proxy -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_security-context.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_security-context.tpl @@ -0,0 +1,23 @@ +{{- /* Defines the container securityContext context */ -}} +{{- define "newrelic.common.securityContext.container" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.containerSecurityContext -}} + {{- toYaml .Values.containerSecurityContext -}} +{{- else if $global.containerSecurityContext -}} + {{- toYaml $global.containerSecurityContext -}} +{{- end -}} +{{- end -}} + + + +{{- /* Defines the pod securityContext context */ -}} +{{- define "newrelic.common.securityContext.pod" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.podSecurityContext -}} + {{- toYaml .Values.podSecurityContext -}} +{{- else if $global.podSecurityContext -}} + {{- toYaml $global.podSecurityContext -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_serviceaccount.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..2d352f6ea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_serviceaccount.tpl @@ -0,0 +1,90 @@ +{{- /* Defines if the service account has to be created or not */ -}} +{{- define "newrelic.common.serviceAccount.create" -}} +{{- $valueFound := false -}} + +{{- /* Look for a global creation of a service account */ -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "create" | kindIs "bool") -}} + {{- $valueFound = true -}} + {{- if .Values.serviceAccount.create -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.serviceAccount.name" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.serviceAccount.create -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Look for a local creation of a service account */ -}} +{{- if not $valueFound -}} + {{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} + {{- $global := index .Values "global" | default dict -}} + {{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "create" | kindIs "bool" -}} + {{- $valueFound = true -}} + {{- if $global.serviceAccount.create -}} + {{- $global.serviceAccount.create -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* In case no serviceAccount value has been found, default to "true" */ -}} +{{- if not $valueFound -}} +true +{{- end -}} +{{- end -}} + + + +{{- /* Defines the name of the service account */ -}} +{{- define "newrelic.common.serviceAccount.name" -}} +{{- $localServiceAccount := "" -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "name" | kindIs "string") -}} + {{- $localServiceAccount = .Values.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := "" -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "name" | kindIs "string" -}} + {{- $globalServiceAccount = $global.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- if (include "newrelic.common.serviceAccount.create" .) -}} + {{- $localServiceAccount | default $globalServiceAccount | default (include "newrelic.common.naming.fullname" .) -}} +{{- else -}} + {{- $localServiceAccount | default $globalServiceAccount | default "default" -}} +{{- end -}} +{{- end -}} + + + +{{- /* Merge the global and local annotations for the service account */ -}} +{{- define "newrelic.common.serviceAccount.annotations" -}} +{{- $localServiceAccount := dict -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if get .Values.serviceAccount "annotations" -}} + {{- $localServiceAccount = .Values.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := dict -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "annotations" -}} + {{- $globalServiceAccount = $global.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $merged := mustMergeOverwrite $globalServiceAccount $localServiceAccount -}} + +{{- if $merged -}} + {{- toYaml $merged -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_staging.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_staging.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the nrStaging toggle. +This helper allows to override the global `.global.nrStaging` with the value of `.nrStaging`. +Returns "true" if `nrStaging` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.nrStaging" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "nrStaging" | kindIs "bool") -}} + {{- if .Values.nrStaging -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.nrStaging" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.nrStaging -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "nrStaging" | kindIs "bool" -}} + {{- if $global.nrStaging -}} + {{- $global.nrStaging -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Returns "true" of "false" directly instead of empty string (Helm falsiness) based on the exit of "newrelic.common.nrStaging" +*/ -}} +{{- define "newrelic.common.nrStaging.value" -}} +{{- if include "newrelic.common.nrStaging" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_tolerations.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_tolerations.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod tolerations */ -}} +{{- define "newrelic.common.tolerations" -}} + {{- if .Values.tolerations -}} + {{- toYaml .Values.tolerations -}} + {{- else if .Values.global -}} + {{- if .Values.global.tolerations -}} + {{- toYaml .Values.global.tolerations -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_verbose-log.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/templates/_verbose-log.tpl @@ -0,0 +1,54 @@ +{{- /* +Abstraction of the verbose toggle. +This helper allows to override the global `.global.verboseLog` with the value of `.verboseLog`. +Returns "true" if `verbose` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.verboseLog" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "verboseLog" | kindIs "bool") -}} + {{- if .Values.verboseLog -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.verboseLog" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.verboseLog -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "verboseLog" | kindIs "bool" -}} + {{- if $global.verboseLog -}} + {{- $global.verboseLog -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return true or false directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsBoolean" -}} +{{- if include "newrelic.common.verboseLog" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return 1 or 0 directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsInt" -}} +{{- if include "newrelic.common.verboseLog" . -}} +1 +{{- else -}} +0 +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/charts/common-library/values.yaml @@ -0,0 +1 @@ +# values are not needed for the library chart, however this file is still needed for helm lint to work. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/ci/test-values.yaml new file mode 100644 index 000000000..3e154e1d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/ci/test-values.yaml @@ -0,0 +1,39 @@ +cluster: test-cluster +licenseKey: pleasePassCIThanks +serviceAccount: + name: newrelic-infra-operator-test +image: + repository: e2e/newrelic-infra-operator + tag: test # Defaults to AppVersion + pullPolicy: IfNotPresent + pullSecrets: + - name: test-pull-secret +admissionWebhooksPatchJob: + volumeMounts: + - name: tmp + mountPath: /tmp + volumes: + - name: tmp + emptyDir: +podAnnotations: + test-annotation: test-value +affinity: + podAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + topologyKey: topology.kubernetes.io/zone + labelSelector: + matchExpressions: + - key: test-key + operator: In + values: + - test-value +tolerations: +- key: "key1" + operator: "Exists" + effect: "NoSchedule" +nodeSelector: + beta.kubernetes.io/os: linux + +fargate: true diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/NOTES.txt b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/NOTES.txt new file mode 100644 index 000000000..5b11d2d83 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/NOTES.txt @@ -0,0 +1,4 @@ +Your deployment of the New Relic Infrastructure Operator is complete. +You can check on the progress of this by running the following command: + + kubectl get deployments -o wide -w --namespace {{ .Release.Namespace }} {{ include "newrelic.common.naming.fullname" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/_helpers.tpl new file mode 100644 index 000000000..8a8858c82 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/_helpers.tpl @@ -0,0 +1,136 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Renders a value that contains template. +Usage: +{{ include "tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }} +*/}} +{{- define "tplvalues.render" -}} + {{- if typeIs "string" .value }} + {{- tpl .value .context }} + {{- else }} + {{- tpl (.value | toYaml) .context }} + {{- end }} +{{- end -}} + +{{- /* +Naming helpers +*/ -}} +{{- define "newrelic-infra-operator.name.admission" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "admission") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.admission" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "admission") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.admission.serviceAccount" -}} +{{- if include "newrelic.common.serviceAccount.create" . -}} + {{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "admission") -}} +{{- else -}} + {{- include "newrelic.common.serviceAccount.name" . -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-infra-operator.name.admission-create" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "admission-create") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.admission-create" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "admission-create") }} +{{- end -}} + +{{- define "newrelic-infra-operator.name.admission-patch" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "admission-patch") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.admission-patch" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "admission-patch") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.self-signed-issuer" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "self-signed-issuer") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.root-cert" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "root-cert") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.root-issuer" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "root-issuer") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.webhook-cert" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "webhook-cert") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.infra-agent" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "infra-agent") }} +{{- end -}} + +{{- define "newrelic-infra-operator.fullname.config" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "config") }} +{{- end -}} + +{{/* +Returns Infra-agent rules +*/}} +{{- define "newrelic-infra-operator.infra-agent-monitoring-rules" -}} +- apiGroups: [""] + resources: + - "nodes" + - "nodes/metrics" + - "nodes/stats" + - "nodes/proxy" + - "pods" + - "services" + - "namespaces" + verbs: ["get", "list"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- end -}} + +{{/* +Returns fargate +*/}} +{{- define "newrelic-infra-operator.fargate" -}} +{{- if .Values.global }} + {{- if .Values.global.fargate }} + {{- .Values.global.fargate -}} + {{- end -}} +{{- else if .Values.fargate }} + {{- .Values.fargate -}} +{{- end -}} +{{- end -}} + +{{/* +Returns fargate configuration for configmap data +*/}} +{{- define "newrelic-infra-operator.fargate-config" -}} +infraAgentInjection: + resourcePrefix: {{ include "newrelic.common.naming.fullname" . }} +{{- if include "newrelic-infra-operator.fargate" . }} +{{- if not .Values.config.infraAgentInjection.policies }} + policies: + - podSelector: + matchExpressions: + - key: "eks.amazonaws.com/fargate-profile" + operator: Exists +{{- end }} + agentConfig: +{{- if not .Values.config.infraAgentInjection.agentConfig.customAttributes }} + customAttributes: + - name: computeType + defaultValue: serverless + - name: fargateProfile + fromLabel: eks.amazonaws.com/fargate-profile +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Returns configmap data +*/}} +{{- define "newrelic-infra-operator.configmap.data" -}} +{{ toYaml (merge (include "newrelic-infra-operator.fargate-config" . | fromYaml) .Values.config) }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrole.yaml new file mode 100644 index 000000000..44c2b3eba --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrole.yaml @@ -0,0 +1,27 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "newrelic-infra-operator.fullname.admission" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic-infra-operator.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + verbs: + - get + - update + {{- if .Values.rbac.pspEnabled }} + - apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ include "newrelic-infra-operator.fullname.admission" . }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrolebinding.yaml new file mode 100644 index 000000000..902206c22 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "newrelic-infra-operator.fullname.admission" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic-infra-operator.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic-infra-operator.fullname.admission" . }} +subjects: + - kind: ServiceAccount + name: {{ include "newrelic-infra-operator.fullname.admission.serviceAccount" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-createSecret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-createSecret.yaml new file mode 100644 index 000000000..022e6254e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-createSecret.yaml @@ -0,0 +1,57 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.admission-create" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic-infra-operator.name.admission-create" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + template: + metadata: + name: {{ include "newrelic-infra-operator.fullname.admission-create" . }} + labels: + app: {{ include "newrelic-infra-operator.name.admission-create" . }} + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" ( list .Values.admissionWebhooksPatchJob.image.pullSecrets ) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + containers: + - name: create + image: {{ include "newrelic.common.images.image" ( dict "defaultRegistry" "registry.k8s.io" "imageRoot" .Values.admissionWebhooksPatchJob.image "context" .) }} + imagePullPolicy: {{ .Values.admissionWebhooksPatchJob.image.pullPolicy }} + args: + - create + - --host={{ include "newrelic.common.naming.fullname" . }},{{ include "newrelic.common.naming.fullname" . }}.{{ .Release.Namespace }}.svc + - --namespace={{ .Release.Namespace }} + - --secret-name={{ include "newrelic-infra-operator.fullname.admission" . }} + - --cert-name=tls.crt + - --key-name=tls.key + {{- if .Values.admissionWebhooksPatchJob.image.volumeMounts }} + volumeMounts: + {{- include "tplvalues.render" ( dict "value" .Values.admissionWebhooksPatchJob.image.volumeMounts "context" $ ) | nindent 10 }} + {{- end }} + {{- if .Values.admissionWebhooksPatchJob.image.volumes }} + volumes: + {{- include "tplvalues.render" ( dict "value" .Values.admissionWebhooksPatchJob.image.volumes "context" $ ) | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + serviceAccountName: {{ include "newrelic-infra-operator.fullname.admission.serviceAccount" . }} + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 -}} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-patchWebhook.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-patchWebhook.yaml new file mode 100644 index 000000000..61e363678 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-patchWebhook.yaml @@ -0,0 +1,57 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.admission-patch" . }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic-infra-operator.name.admission-patch" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + template: + metadata: + name: {{ include "newrelic-infra-operator.fullname.admission-patch" . }} + labels: + app: {{ include "newrelic-infra-operator.name.admission-patch" . }} + {{- include "newrelic.common.labels" . | nindent 8 }} + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" ( list .Values.admissionWebhooksPatchJob.image.pullSecrets ) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + containers: + - name: patch + image: {{ include "newrelic.common.images.image" ( dict "defaultRegistry" "registry.k8s.io" "imageRoot" .Values.admissionWebhooksPatchJob.image "context" .) }} + imagePullPolicy: {{ .Values.admissionWebhooksPatchJob.image.pullPolicy }} + args: + - patch + - --webhook-name={{ include "newrelic.common.naming.fullname" . }} + - --namespace={{ .Release.Namespace }} + - --secret-name={{ include "newrelic-infra-operator.fullname.admission" . }} + - --patch-failure-policy=Ignore + - --patch-validating=false + {{- if .Values.admissionWebhooksPatchJob.image.volumeMounts }} + volumeMounts: + {{- include "tplvalues.render" ( dict "value" .Values.admissionWebhooksPatchJob.image.volumeMounts "context" $ ) | nindent 10 }} + {{- end }} + {{- if .Values.admissionWebhooksPatchJob.image.volumes }} + volumes: + {{- include "tplvalues.render" ( dict "value" .Values.admissionWebhooksPatchJob.image.volumes "context" $ ) | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + serviceAccountName: {{ include "newrelic-infra-operator.fullname.admission.serviceAccount" . }} + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 -}} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/psp.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/psp.yaml new file mode 100644 index 000000000..64237abb4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/psp.yaml @@ -0,0 +1,50 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled) (.Values.rbac.pspEnabled)) }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ include "newrelic-infra-operator.fullname.admission" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic-infra-operator.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + privileged: false + # Required to prevent escalations to root. + # allowPrivilegeEscalation: false + # This is redundant with non-root + disallow privilege escalation, + # but we can provide it for defense in depth. + # requiredDropCapabilities: + # - ALL + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + - 'persistentVolumeClaim' + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} + hostIPC: false + hostPID: false + runAsUser: + # Permits the container to run with root privileges as well. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 0 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/role.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/role.yaml new file mode 100644 index 000000000..e3213f7c5 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/role.yaml @@ -0,0 +1,21 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.admission" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic-infra-operator.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/rolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/rolebinding.yaml new file mode 100644 index 000000000..67eb79298 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/rolebinding.yaml @@ -0,0 +1,21 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.admission" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic-infra-operator.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "newrelic-infra-operator.fullname.admission" . }} +subjects: + - kind: ServiceAccount + name: {{ include "newrelic-infra-operator.fullname.admission.serviceAccount" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/serviceaccount.yaml new file mode 100644 index 000000000..18eb7347d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- $createServiceAccount := include "newrelic.common.serviceAccount.create" . -}} +{{- if (and $createServiceAccount (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.admission.serviceAccount" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic-infra-operator.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/mutatingWebhookConfiguration.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/mutatingWebhookConfiguration.yaml new file mode 100644 index 000000000..efa605255 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/admission-webhooks/mutatingWebhookConfiguration.yaml @@ -0,0 +1,32 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} +{{- if .Values.certManager.enabled }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-root-cert" .Release.Namespace (include "newrelic.common.naming.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-root-cert" .Release.Namespace (include "newrelic.common.naming.fullname" .) | quote }} +{{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +webhooks: +- name: newrelic-infra-operator.newrelic.com + clientConfig: + service: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + path: "/mutate-v1-pod" +{{- if not .Values.certManager.enabled }} + caBundle: "" +{{- end }} + rules: + - operations: ["CREATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + failurePolicy: Ignore + timeoutSeconds: {{ .Values.timeoutSeconds }} + sideEffects: NoneOnDryRun + admissionReviewVersions: + - v1 + reinvocationPolicy: IfNeeded diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/cert-manager.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/cert-manager.yaml new file mode 100644 index 000000000..800dc2453 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/cert-manager.yaml @@ -0,0 +1,52 @@ +{{ if .Values.certManager.enabled }} +--- +# Create a selfsigned Issuer, in order to create a root CA certificate for +# signing webhook serving certificates +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.self-signed-issuer" . }} +spec: + selfSigned: {} +--- +# Generate a CA Certificate used to sign certificates for the webhook +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.root-cert" . }} +spec: + secretName: {{ include "newrelic-infra-operator.fullname.root-cert" . }} + duration: 43800h # 5y + issuerRef: + name: {{ include "newrelic-infra-operator.fullname.self-signed-issuer" . }} + commonName: "ca.webhook.nri" + isCA: true +--- +# Create an Issuer that uses the above generated CA certificate to issue certs +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.root-issuer" . }} +spec: + ca: + secretName: {{ include "newrelic-infra-operator.fullname.root-cert" . }} +--- +# Finally, generate a serving certificate for the webhook to use +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.webhook-cert" . }} +spec: + secretName: {{ include "newrelic-infra-operator.fullname.admission" . }} + duration: 8760h # 1y + issuerRef: + name: {{ include "newrelic-infra-operator.fullname.root-issuer" . }} + dnsNames: + - {{ include "newrelic.common.naming.fullname" . }} + - {{ include "newrelic.common.naming.fullname" . }}.{{ .Release.Namespace }} + - {{ include "newrelic.common.naming.fullname" . }}.{{ .Release.Namespace }}.svc +{{ end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/clusterrole.yaml new file mode 100644 index 000000000..cb20e310d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/clusterrole.yaml @@ -0,0 +1,39 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + {{/* Allow creating and updating secrets with license key for infra agent. */ -}} + - apiGroups: [""] + resources: + - "secrets" + verbs: ["get", "update", "patch"] + resourceNames: [ {{ include "newrelic-infra-operator.fullname.config" . | quote }} ] + {{/* resourceNames used above do not support "create" verb. */ -}} + - apiGroups: [""] + resources: + - "secrets" + verbs: ["create"] + {{/* "list" and "watch" are required for controller-runtime caching. */ -}} + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterrolebindings"] + verbs: ["list", "watch", "get"] + {{/* Our controller needs permission to add the ServiceAccounts from the user to the -infra-agent CRB. */ -}} + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterrolebindings"] + verbs: ["update"] + resourceNames: [ {{ include "newrelic-infra-operator.fullname.infra-agent" . | quote }} ] + {{- /* Controller must have permissions it will grant to other ServiceAccounts. */ -}} + {{- include "newrelic-infra-operator.infra-agent-monitoring-rules" . | nindent 2 }} +--- +{{/* infra-agent is the ClusterRole to be used by the injected agents to get metrics */}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "newrelic-infra-operator.fullname.infra-agent" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + {{- include "newrelic-infra-operator.infra-agent-monitoring-rules" . | nindent 2 }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..1f5f8b89b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/clusterrolebinding.yaml @@ -0,0 +1,26 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic.common.naming.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +--- +{{/* infra-agent is the ClusterRoleBinding to be used by the ServiceAccounts of the injected agents */}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "newrelic-infra-operator.fullname.infra-agent" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic-infra-operator.fullname.infra-agent" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/configmap.yaml new file mode 100644 index 000000000..fdb4a1e3b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-infra-operator.fullname.config" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + operator.yaml: {{- include "newrelic-infra-operator.configmap.data" . | toYaml | nindent 4 }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/deployment.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/deployment.yaml new file mode 100644 index 000000000..40f389887 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/deployment.yaml @@ -0,0 +1,92 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- if .Values.podAnnotations }} + {{- toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} + spec: + serviceAccountName: {{ template "newrelic.common.serviceAccount.name" . }} + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" ( list .Values.image.pullSecrets ) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + containers: + - name: {{ include "newrelic.common.naming.name" . }} + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.image "context" .) }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- with include "newrelic.common.securityContext.container" . }} + securityContext: + {{- . | nindent 10 }} + {{- end }} + env: + - name: CLUSTER_NAME + value: {{ include "newrelic.common.cluster" . }} + - name: NRIA_LICENSE_KEY + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} + volumeMounts: + - name: config + mountPath: /etc/newrelic/newrelic-infra-operator/ + - name: tls-key-cert-pair + mountPath: /tmp/k8s-webhook-server/serving-certs/ + readinessProbe: + httpGet: + path: /healthz + port: 9440 + initialDelaySeconds: 1 + periodSeconds: 1 + {{- if .Values.resources }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + {{- end }} + volumes: + - name: config + configMap: + name: {{ include "newrelic-infra-operator.fullname.config" . }} + - name: tls-key-cert-pair + secret: + secretName: {{ include "newrelic-infra-operator.fullname.admission" . }} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 -}} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 8 -}} + {{- end }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} + {{- if include "newrelic.common.hostNetwork" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/secret.yaml new file mode 100644 index 000000000..f558ee86c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/secret.yaml @@ -0,0 +1,2 @@ +{{- /* Common library will take care of creating the secret or not. */}} +{{- include "newrelic.common.license.secret" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/service.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/service.yaml new file mode 100644 index 000000000..04af4d09c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 4 }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/serviceaccount.yaml new file mode 100644 index 000000000..b1e74523e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- if include "newrelic.common.serviceAccount.annotations" . }} + annotations: + {{- include "newrelic.common.serviceAccount.annotations" . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/deployment_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/deployment_test.yaml new file mode 100644 index 000000000..a1ffa88d0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/deployment_test.yaml @@ -0,0 +1,32 @@ +suite: test cluster environment variable setup +templates: + - templates/deployment.yaml + - templates/configmap.yaml + - templates/secret.yaml +release: + name: my-release + namespace: my-namespac +tests: + - it: has a linux node selector by default + set: + cluster: my-cluster + licenseKey: use-whatever + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + template: templates/deployment.yaml + - it: has a linux node selector and additional selectors + set: + cluster: my-cluster + licenseKey: use-whatever + nodeSelector: + aCoolTestLabel: aCoolTestValue + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + aCoolTestLabel: aCoolTestValue + template: templates/deployment.yaml diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/job_patch_psp_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/job_patch_psp_test.yaml new file mode 100644 index 000000000..78f1b1f6a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/job_patch_psp_test.yaml @@ -0,0 +1,23 @@ +suite: test rendering for PSPs +templates: + - templates/admission-webhooks/job-patch/psp.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: If PSPs are enabled PodSecurityPolicy is rendered + set: + cluster: test-cluster + licenseKey: use-whatever + rbac: + pspEnabled: true + asserts: + - hasDocuments: + count: 1 + - it: If PSPs are disabled PodSecurityPolicy isn't rendered + set: + cluster: test-cluster + licenseKey: use-whatever + asserts: + - hasDocuments: + count: 0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/job_serviceaccount_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/job_serviceaccount_test.yaml new file mode 100644 index 000000000..c6acda2db --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/job_serviceaccount_test.yaml @@ -0,0 +1,64 @@ +suite: test job' serviceAccount +templates: + - templates/admission-webhooks/job-patch/job-createSecret.yaml + - templates/admission-webhooks/job-patch/job-patchWebhook.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: RBAC points to the service account that is created by default + set: + cluster: test-cluster + licenseKey: use-whatever + rbac.create: true + serviceAccount.create: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: my-release-newrelic-infra-operator-admission + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + cluster: test-cluster + licenseKey: use-whatever + rbac.create: true + serviceAccount.create: false + serviceAccount.name: sa-test + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: sa-test + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + cluster: test-cluster + licenseKey: use-whatever + rbac.create: true + serviceAccount.create: false + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: default + + - it: has a linux node selector by default + set: + cluster: my-cluster + licenseKey: use-whatever + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + + - it: has a linux node selector and additional selectors + set: + cluster: my-cluster + licenseKey: use-whatever + nodeSelector: + aCoolTestLabel: aCoolTestValue + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + aCoolTestLabel: aCoolTestValue diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/rbac_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/rbac_test.yaml new file mode 100644 index 000000000..03473cb39 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/tests/rbac_test.yaml @@ -0,0 +1,41 @@ +suite: test RBAC creation +templates: + - templates/admission-webhooks/job-patch/rolebinding.yaml + - templates/admission-webhooks/job-patch/clusterrolebinding.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: RBAC points to the service account that is created by default + set: + cluster: test-cluster + licenseKey: use-whatever + rbac.create: true + serviceAccount.create: true + asserts: + - equal: + path: subjects[0].name + value: my-release-newrelic-infra-operator-admission + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + cluster: test-cluster + licenseKey: use-whatever + rbac.create: true + serviceAccount.create: false + serviceAccount.name: sa-test + asserts: + - equal: + path: subjects[0].name + value: sa-test + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + cluster: test-cluster + licenseKey: use-whatever + rbac.create: true + serviceAccount.create: false + asserts: + - equal: + path: subjects[0].name + value: default diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/values.yaml new file mode 100644 index 000000000..3dd6fd055 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infra-operator/values.yaml @@ -0,0 +1,222 @@ +# -- Override the name of the chart +nameOverride: "" +# -- Override the full name of the release +fullnameOverride: "" + +# -- Name of the Kubernetes cluster monitored. Mandatory. Can be configured also with `global.cluster` +cluster: "" +# -- This set this license key to use. Can be configured also with `global.licenseKey` +licenseKey: "" +# -- In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` +customSecretName: "" +# -- In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` +customSecretLicenseKey: "" + +# -- Image for the New Relic Infrastructure Operator +# @default -- See `values.yaml` +image: + repository: newrelic/newrelic-infra-operator + tag: "" + pullPolicy: IfNotPresent + # -- The secrets that are needed to pull images from a custom registry. + pullSecrets: [] + # - name: regsecret + +# -- Image used to create certificates and inject them to the admission webhook +# @default -- See `values.yaml` +admissionWebhooksPatchJob: + image: + registry: # Defaults to registry.k8s.io + repository: ingress-nginx/kube-webhook-certgen + tag: v1.3.0 + pullPolicy: IfNotPresent + # -- The secrets that are needed to pull images from a custom registry. + pullSecrets: [] + # - name: regsecret + + # -- Volume mounts to add to the job, you might want to mount tmp if Pod Security Policies. + # Enforce a read-only root. + volumeMounts: [] + # - name: tmp + # mountPath: /tmp + # -- Volumes to add to the job container. + volumes: [] + # - name: tmp + # emptyDir: {} + +rbac: + # rbac.pspEnabled -- Whether the chart should create Pod Security Policy objects. + pspEnabled: false + +replicas: 1 + +# -- Resources available for this pod +resources: + limits: + memory: 80M + requests: + cpu: 100m + memory: 30M + +# -- Settings controlling ServiceAccount creation +# @default -- See `values.yaml` +serviceAccount: + # serviceAccount.create -- (bool) Specifies whether a ServiceAccount should be created + # @default -- `true` + create: + # If not set and create is true, a name is generated using the fullname template + name: "" + # Specify any annotations to add to the ServiceAccount + annotations: + +# -- Annotations to add to the pod. +podAnnotations: {} + +# -- Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` +priorityClassName: "" +# -- (bool) Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` +# @default -- `false` +hostNetwork: +# -- Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` +dnsConfig: {} +# -- Sets security context (at pod level). Can be configured also with `global.podSecurityContext` +podSecurityContext: + fsGroup: 1001 + runAsUser: 1001 + runAsGroup: 1001 +# -- Sets security context (at container level). Can be configured also with `global.containerSecurityContext` +containerSecurityContext: {} + +# -- Sets pod/node affinities. Can be configured also with `global.affinity` +affinity: {} +# -- Sets pod's node selector. Can be configured also with `global.nodeSelector` +nodeSelector: {} +# -- Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` +tolerations: [] + +certManager: + # certManager.enabled -- Use cert manager for webhook certs + enabled: false + +# -- Webhook timeout +# Ref: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts +timeoutSeconds: 10 + +# -- Operator configuration +# @default -- See `values.yaml` +config: + # -- IgnoreMutationErrors instruments the operator to ignore injection error instead of failing. + # If set to false errors of the injection could block the creation of pods. + ignoreMutationErrors: true + + # -- configuration of the sidecar injection webhook + # @default -- See `values.yaml` + infraAgentInjection: +# policies: +# - podSelector: +# matchExpressions: +# - key: app +# operator: In +# values: [ "nginx-sidecar" ] +# + # All policies are ORed, if one policy matches the sidecar is injected. + # Within a policy PodSelectors, NamespaceSelector and NamespaceName are ANDed, any of these, if not specified, is ignored. + # The following policy is injected if global.fargate=true and matches all pods belonging to any fargate profile. + # policies: + # - podSelector: + # matchExpressions: + # - key: "eks.amazonaws.com/fargate-profile" + # operator: Exists + # Also NamespaceName and NamespaceSelector can be leveraged. + # namespaceName: "my-namespace" + # namespaceSelector: {} + + # -- agentConfig contains the configuration for the container agent injected + # @default -- See `values.yaml` + agentConfig: + # Custom Attributes allows to pass any custom attribute to the injected infra agents. + # The value is computed either from the defaultValue or taken at injected time from Label specified in "fromLabel". + # Either the label should exist or the default should be specified in order to have the injection working. + # customAttributes: + # - name: computeType + # defaultValue: serverless + # - name: fargateProfile + # fromLabel: eks.amazonaws.com/fargate-profile + + # -- Image of the infrastructure agent to be injected. + # @default -- See `values.yaml` + image: + repository: newrelic/infrastructure-k8s + tag: 2.13.15-unprivileged + pullPolicy: IfNotPresent + + # -- configSelectors is the way to configure resource requirements and extra envVars of the injected sidecar container. + # When mutating it will be applied the first configuration having the labelSelector matching with the mutating pod. + # @default -- See `values.yaml` + configSelectors: + - resourceRequirements: # resourceRequirements to apply to the injected sidecar. + limits: + memory: 100M + cpu: 200m + requests: + memory: 50M + cpu: 100m + extraEnvVars: # extraEnvVars to pass to the injected sidecar. + DISABLE_KUBE_STATE_METRICS: "true" + # NRIA_VERBOSE: "1" + labelSelector: + matchExpressions: + - key: "app.kubernetes.io/name" + operator: NotIn + values: ["kube-state-metrics"] + - key: "app" + operator: NotIn + values: ["kube-state-metrics"] + - key: "k8s-app" + operator: NotIn + values: ["kube-state-metrics"] + + - resourceRequirements: + limits: + memory: 300M + cpu: 300m + requests: + memory: 150M + cpu: 150m + labelSelector: + matchLabels: + k8s-app: kube-state-metrics + # extraEnvVars: + # NRIA_VERBOSE: "1" + + - resourceRequirements: + limits: + memory: 300M + cpu: 300m + requests: + memory: 150M + cpu: 150m + labelSelector: + matchLabels: + app: kube-state-metrics + # extraEnvVars: + # NRIA_VERBOSE: "1" + + - resourceRequirements: + limits: + memory: 300M + cpu: 300m + requests: + memory: 150M + cpu: 150m + labelSelector: + matchLabels: + app.kubernetes.io/name: kube-state-metrics + # extraEnvVars: + # NRIA_VERBOSE: "1" + + # pod Security Context of the sidecar injected. + # Notice that ReadOnlyRootFilesystem and AllowPrivilegeEscalation enforced respectively to true and to false. + # podSecurityContext: + # RunAsUser: + # RunAsGroup: diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/.helmignore new file mode 100644 index 000000000..2bfa6a4d9 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/.helmignore @@ -0,0 +1 @@ +tests/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/Chart.lock new file mode 100644 index 000000000..e921cc491 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +digest: sha256:fa87cb007564a39a72739a3e850a91d6b03c0fc27a1115deac042b3ef77b4142 +generated: "2024-06-24T12:11:50.10851808Z" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/Chart.yaml new file mode 100644 index 000000000..a58fea9f9 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +appVersion: 3.29.2 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +description: A Helm chart to deploy the New Relic Kubernetes monitoring solution +home: https://docs.newrelic.com/docs/kubernetes-pixie/kubernetes-integration/get-started/introduction-kubernetes-integration/ +icon: https://newrelic.com/themes/custom/curio/assets/mediakit/NR_logo_Horizontal.svg +keywords: +- infrastructure +- newrelic +- monitoring +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +name: newrelic-infrastructure +sources: +- https://github.com/newrelic/nri-kubernetes/ +- https://github.com/newrelic/nri-kubernetes/tree/main/charts/newrelic-infrastructure +- https://github.com/newrelic/infrastructure-agent/ +version: 3.34.2 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/README.md new file mode 100644 index 000000000..923b6109b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/README.md @@ -0,0 +1,220 @@ +# newrelic-infrastructure + +A Helm chart to deploy the New Relic Kubernetes monitoring solution + +**Homepage:** + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add nri-kubernetes https://newrelic.github.io/nri-kubernetes +helm upgrade --install newrelic-infrastructure nri-kubernetes/newrelic-infrastructure -f your-custom-values.yaml +``` + +## Source Code + +* +* +* + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Chart particularities + +### Low data mode +There are two mechanisms to reduce the amount of data that this integration sends to New Relic. See this snippet from the `values.yaml` file: +```yaml +common: + config: + interval: 15s + +lowDataMode: false +``` + +The `lowDataMode` toggle is the simplest way to reduce data send to Newrelic. Setting it to `true` changes the default scrape interval from 15 seconds +(the default) to 30 seconds. + +If you need for some reason to fine-tune the number of seconds you can use `common.config.interval` directly. If you take a look at the `values.yaml` +file, the value there is `nil`. If any value is set there, the `lowDataMode` toggle is ignored as this value takes precedence. + +Setting this interval above 40 seconds can make you experience issues with the Kubernetes Cluster Explorer so this chart limits setting the interval +inside the range of 10 to 40 seconds. + +### Affinities and tolerations + +The New Relic common library allows to set affinities, tolerations, and node selectors globally using e.g. `.global.affinity` to ease the configuration +when you use this chart using `nri-bundle`. This chart has an extra level of granularity to the components that it deploys: +control plane, ksm, and kubelet. + +Take this snippet as an example: +```yaml +global: + affinity: {} +affinity: {} + +kubelet: + affinity: {} +ksm: + affinity: {} +controlPlane: + affinity: {} +``` + +The order to set an affinity is to set first any `kubelet.affinity`, `ksm.affinity`, or `controlPlane.affinity`. If these values are empty the chart +fallbacks to `affinity` (at root level), and if that value is empty, the chart fallbacks to `global.affinity`. + +The same procedure applies to `nodeSelector` and `tolerations`. + +On the other hand, some components have affinities and tolerations predefined e.g. to be able to run kubelet pods on nodes that are tainted as master +nodes or to schedule the KSM scraper on the same node of KSM to reduce the inter-node traffic. + +If you are having problems assigning pods to nodes it may be because of this. Take a look at the [`values.yaml`](values.yaml) to see if the pod that is +not having your expected behavior has any predefined value. + +### `hostNetwork` toggle + +In versions below v3, changing the `privileged` mode affected the `hostNetwork`. We changed this behavior and now you can set pods to use `hostNetwork` +using the corresponding [flags from the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md) +(`.global.hostNetwork` and `.hostNetwork`) but the component that scrapes data from the control plane has always set `hostNetwork` enabled by default +(Look in the [`values.yaml`](values.yaml) for `controlPlane.hostNetwork: true`) + +This is because the most common configuration of the control plane components is to be configured to listen only to `localhost`. + +If your cluster security policy does not allow to use `hostNetwork`, you can disable it control plane monitoring by setting `controlPlane.enabled` to +`false.` + +### `privileged` toggle + +The default value for `privileged` [from the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md) is +`false` but in this particular this chart it is set to `true` (Look in the [`values.yaml`](values.yaml) for `privileged: true`) + +This is because when `kubelet` pods need to run in privileged mode to fetch cpu, memory, process, and network metrics of your nodes. + +If your cluster security policy does not allow to have `privileged` in your pod' security context, you can disable it by setting `privileged` to +`false` taking into account that you will lose all the metrics from the host and some metadata from the host that are added to the metrics of the +integrations that you have configured. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Sets pod/node affinities set almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) | +| cluster | string | `""` | Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster` | +| common | object | See `values.yaml` | Config that applies to all instances of the solution: kubelet, ksm, control plane and sidecars. | +| common.agentConfig | object | `{}` | Config for the Infrastructure agent. Will be used by the forwarder sidecars and the agent running integrations. See: https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ | +| common.config.interval | duration | `15s` (See [Low data mode](README.md#low-data-mode)) | Intervals larger than 40s are not supported and will cause the NR UI to not behave properly. Any non-nil value will override the `lowDataMode` default. | +| common.config.namespaceSelector | object | `{}` | Config for filtering ksm and kubelet metrics by namespace. | +| containerSecurityContext | object | `{}` | Sets security context (at container level). Can be configured also with `global.containerSecurityContext` | +| controlPlane | object | See `values.yaml` | Configuration for the control plane scraper. | +| controlPlane.affinity | object | Deployed only in master nodes. | Affinity for the control plane DaemonSet. | +| controlPlane.agentConfig | object | `{}` | Config for the Infrastructure agent that will forward the metrics to the backend. It will be merged with the configuration in `.common.agentConfig` See: https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ | +| controlPlane.config.apiServer | object | Common settings for most K8s distributions. | API Server monitoring configuration | +| controlPlane.config.apiServer.enabled | bool | `true` | Enable API Server monitoring | +| controlPlane.config.controllerManager | object | Common settings for most K8s distributions. | Controller manager monitoring configuration | +| controlPlane.config.controllerManager.enabled | bool | `true` | Enable controller manager monitoring. | +| controlPlane.config.etcd | object | Common settings for most K8s distributions. | etcd monitoring configuration | +| controlPlane.config.etcd.enabled | bool | `true` | Enable etcd monitoring. Might require manual configuration in some environments. | +| controlPlane.config.retries | int | `3` | Number of retries after timeout expired | +| controlPlane.config.scheduler | object | Common settings for most K8s distributions. | Scheduler monitoring configuration | +| controlPlane.config.scheduler.enabled | bool | `true` | Enable scheduler monitoring. | +| controlPlane.config.timeout | string | `"10s"` | Timeout for the Kubernetes APIs contacted by the integration | +| controlPlane.enabled | bool | `true` | Deploy control plane monitoring component. | +| controlPlane.hostNetwork | bool | `true` | Run Control Plane scraper with `hostNetwork`. `hostNetwork` is required for most control plane configurations, as they only accept connections from localhost. | +| controlPlane.kind | string | `"DaemonSet"` | How to deploy the control plane scraper. If autodiscovery is in use, it should be `DaemonSet`. Advanced users using static endpoints set this to `Deployment` to avoid reporting metrics twice. | +| controlPlane.tolerations | list | Schedules in all tainted nodes | Tolerations for the control plane DaemonSet. | +| customAttributes | object | `{}` | Adds extra attributes to the cluster and all the metrics emitted to the backend. Can be configured also with `global.customAttributes` | +| customSecretLicenseKey | string | `""` | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` | +| customSecretName | string | `""` | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` | +| dnsConfig | object | `{}` | Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` | +| enableProcessMetrics | bool | `false` | Collect detailed metrics from processes running in the host. This defaults to true for accounts created before July 20, 2020. ref: https://docs.newrelic.com/docs/release-notes/infrastructure-release-notes/infrastructure-agent-release-notes/new-relic-infrastructure-agent-1120 | +| fedramp.enabled | bool | `false` | Enables FedRAMP. Can be configured also with `global.fedramp.enabled` | +| fullnameOverride | string | `""` | Override the full name of the release | +| hostNetwork | bool | `false` | Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` | +| images | object | See `values.yaml` | Images used by the chart for the integration and agents. | +| images.agent | object | See `values.yaml` | Image for the New Relic Infrastructure Agent plus integrations. | +| images.forwarder | object | See `values.yaml` | Image for the New Relic Infrastructure Agent sidecar. | +| images.integration | object | See `values.yaml` | Image for the New Relic Kubernetes integration. | +| images.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | +| integrations | object | `{}` | Config files for other New Relic integrations that should run in this cluster. | +| ksm | object | See `values.yaml` | Configuration for the Deployment that collects state metrics from KSM (kube-state-metrics). | +| ksm.affinity | object | Deployed in the same node as KSM | Affinity for the KSM Deployment. | +| ksm.agentConfig | object | `{}` | Config for the Infrastructure agent that will forward the metrics to the backend. It will be merged with the configuration in `.common.agentConfig` See: https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ | +| ksm.config.retries | int | `3` | Number of retries after timeout expired | +| ksm.config.scheme | string | `"http"` | Scheme to use to connect to kube-state-metrics. Supported values are `http` and `https`. | +| ksm.config.selector | string | `"app.kubernetes.io/name=kube-state-metrics"` | Label selector that will be used to automatically discover an instance of kube-state-metrics running in the cluster. | +| ksm.config.timeout | string | `"10s"` | Timeout for the ksm API contacted by the integration | +| ksm.enabled | bool | `true` | Enable cluster state monitoring. Advanced users only. Setting this to `false` is not supported and will break the New Relic experience. | +| ksm.hostNetwork | bool | Not set | Sets pod's hostNetwork. When set bypasses global/common variable | +| ksm.resources | object | 100m/150M -/850M | Resources for the KSM scraper pod. Keep in mind that sharding is not supported at the moment, so memory usage for this component ramps up quickly on large clusters. | +| ksm.tolerations | list | Schedules in all tainted nodes | Tolerations for the KSM Deployment. | +| kubelet | object | See `values.yaml` | Configuration for the DaemonSet that collects metrics from the Kubelet. | +| kubelet.agentConfig | object | `{}` | Config for the Infrastructure agent that will forward the metrics to the backend and will run the integrations in this cluster. It will be merged with the configuration in `.common.agentConfig`. You can see all the agent configurations in [New Relic docs](https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/) e.g. you can set `passthrough_environment` int the [config file](https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/configure-infrastructure-agent/#config-file) so the agent let use that environment variables to the integrations. | +| kubelet.config.retries | int | `3` | Number of retries after timeout expired | +| kubelet.config.scraperMaxReruns | int | `4` | Max number of scraper rerun when scraper runtime error happens | +| kubelet.config.timeout | string | `"10s"` | Timeout for the kubelet APIs contacted by the integration | +| kubelet.enabled | bool | `true` | Enable kubelet monitoring. Advanced users only. Setting this to `false` is not supported and will break the New Relic experience. | +| kubelet.extraEnv | list | `[]` | Add user environment variables to the agent | +| kubelet.extraEnvFrom | list | `[]` | Add user environment from configMaps or secrets as variables to the agent | +| kubelet.extraVolumeMounts | list | `[]` | Defines where to mount volumes specified with `extraVolumes` | +| kubelet.extraVolumes | list | `[]` | Volumes to mount in the containers | +| kubelet.hostNetwork | bool | Not set | Sets pod's hostNetwork. When set bypasses global/common variable | +| kubelet.tolerations | list | Schedules in all tainted nodes | Tolerations for the control plane DaemonSet. | +| labels | object | `{}` | Additional labels for chart objects. Can be configured also with `global.labels` | +| licenseKey | string | `""` | This set this license key to use. Can be configured also with `global.licenseKey` | +| lowDataMode | bool | `false` (See [Low data mode](README.md#low-data-mode)) | Send less data by incrementing the interval from `15s` (the default when `lowDataMode` is `false` or `nil`) to `30s`. Non-nil values of `common.config.interval` will override this value. | +| nameOverride | string | `""` | Override the name of the chart | +| nodeSelector | object | `{}` | Sets pod's node selector almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) | +| nrStaging | bool | `false` | Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` | +| podAnnotations | object | `{}` | Annotations to be added to all pods created by the integration. | +| podLabels | object | `{}` | Additional labels for chart pods. Can be configured also with `global.podLabels` | +| podSecurityContext | object | `{}` | Sets security context (at pod level). Can be configured also with `global.podSecurityContext` | +| priorityClassName | string | `""` | Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` | +| privileged | bool | `true` | Run the integration with full access to the host filesystem and network. Running in this mode allows reporting fine-grained cpu, memory, process and network metrics for your nodes. | +| proxy | string | `""` | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port`. Can be configured also with `global.proxy` | +| rbac.create | bool | `true` | Whether the chart should automatically create the RBAC objects required to run. | +| rbac.pspEnabled | bool | `false` | Whether the chart should create Pod Security Policy objects. | +| selfMonitoring.pixie.enabled | bool | `false` | Enables the Pixie Health Check nri-flex config. This Flex config performs periodic checks of the Pixie /healthz and /statusz endpoints exposed by the Pixie Cloud Connector. A status for each endpoint is sent to New Relic in a pixieHealthCheck event. | +| serviceAccount | object | See `values.yaml` | Settings controlling ServiceAccount creation. | +| serviceAccount.create | bool | `true` | Whether the chart should automatically create the ServiceAccount objects required to run. | +| sink.http.probeBackoff | string | `"5s"` | The amount of time the scraper container to backoff when it fails to probe infra agent sidecar. | +| sink.http.probeTimeout | string | `"90s"` | The amount of time the scraper container to probe infra agent sidecar container before giving up and restarting during pod starts. | +| strategy | object | `type: Recreate` | Update strategy for the deployed Deployments. | +| tolerations | list | `[]` | Sets pod's tolerations to node taints almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) | +| updateStrategy | object | See `values.yaml` | Update strategy for the deployed DaemonSets. | +| verboseLog | bool | `false` | Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` | + +## Maintainers + +* [juanjjaramillo](https://github.com/juanjjaramillo) +* [csongnr](https://github.com/csongnr) +* [dbudziwojskiNR](https://github.com/dbudziwojskiNR) + +## Past Contributors + +Previous iterations of this chart started as a community project in the [stable Helm chart repository](github.com/helm/charts/). New Relic is very thankful for all the 15+ community members that contributed and helped maintain the chart there over the years: + +* coreypobrien +* sstarcher +* jmccarty3 +* slayerjain +* ryanhope2 +* rk295 +* michaelajr +* isindir +* idirouhab +* ismferd +* enver +* diclophis +* jeffdesc +* costimuraru +* verwilst +* ezelenka diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/README.md.gotmpl new file mode 100644 index 000000000..84f2f9083 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/README.md.gotmpl @@ -0,0 +1,137 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add nri-kubernetes https://newrelic.github.io/nri-kubernetes +helm upgrade --install newrelic-infrastructure nri-kubernetes/newrelic-infrastructure -f your-custom-values.yaml +``` + +{{ template "chart.sourcesSection" . }} + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Chart particularities + +### Low data mode +There are two mechanisms to reduce the amount of data that this integration sends to New Relic. See this snippet from the `values.yaml` file: +```yaml +common: + config: + interval: 15s + +lowDataMode: false +``` + +The `lowDataMode` toggle is the simplest way to reduce data send to Newrelic. Setting it to `true` changes the default scrape interval from 15 seconds +(the default) to 30 seconds. + +If you need for some reason to fine-tune the number of seconds you can use `common.config.interval` directly. If you take a look at the `values.yaml` +file, the value there is `nil`. If any value is set there, the `lowDataMode` toggle is ignored as this value takes precedence. + +Setting this interval above 40 seconds can make you experience issues with the Kubernetes Cluster Explorer so this chart limits setting the interval +inside the range of 10 to 40 seconds. + +### Affinities and tolerations + +The New Relic common library allows to set affinities, tolerations, and node selectors globally using e.g. `.global.affinity` to ease the configuration +when you use this chart using `nri-bundle`. This chart has an extra level of granularity to the components that it deploys: +control plane, ksm, and kubelet. + +Take this snippet as an example: +```yaml +global: + affinity: {} +affinity: {} + +kubelet: + affinity: {} +ksm: + affinity: {} +controlPlane: + affinity: {} +``` + +The order to set an affinity is to set first any `kubelet.affinity`, `ksm.affinity`, or `controlPlane.affinity`. If these values are empty the chart +fallbacks to `affinity` (at root level), and if that value is empty, the chart fallbacks to `global.affinity`. + +The same procedure applies to `nodeSelector` and `tolerations`. + +On the other hand, some components have affinities and tolerations predefined e.g. to be able to run kubelet pods on nodes that are tainted as master +nodes or to schedule the KSM scraper on the same node of KSM to reduce the inter-node traffic. + +If you are having problems assigning pods to nodes it may be because of this. Take a look at the [`values.yaml`](values.yaml) to see if the pod that is +not having your expected behavior has any predefined value. + +### `hostNetwork` toggle + +In versions below v3, changing the `privileged` mode affected the `hostNetwork`. We changed this behavior and now you can set pods to use `hostNetwork` +using the corresponding [flags from the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md) +(`.global.hostNetwork` and `.hostNetwork`) but the component that scrapes data from the control plane has always set `hostNetwork` enabled by default +(Look in the [`values.yaml`](values.yaml) for `controlPlane.hostNetwork: true`) + +This is because the most common configuration of the control plane components is to be configured to listen only to `localhost`. + +If your cluster security policy does not allow to use `hostNetwork`, you can disable it control plane monitoring by setting `controlPlane.enabled` to +`false.` + +### `privileged` toggle + +The default value for `privileged` [from the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md) is +`false` but in this particular this chart it is set to `true` (Look in the [`values.yaml`](values.yaml) for `privileged: true`) + +This is because when `kubelet` pods need to run in privileged mode to fetch cpu, memory, process, and network metrics of your nodes. + +If your cluster security policy does not allow to have `privileged` in your pod' security context, you can disable it by setting `privileged` to +`false` taking into account that you will lose all the metrics from the host and some metadata from the host that are added to the metrics of the +integrations that you have configured. + +{{ template "chart.valuesSection" . }} + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +## Past Contributors + +Previous iterations of this chart started as a community project in the [stable Helm chart repository](github.com/helm/charts/). New Relic is very thankful for all the 15+ community members that contributed and helped maintain the chart there over the years: + +* coreypobrien +* sstarcher +* jmccarty3 +* slayerjain +* ryanhope2 +* rk295 +* michaelajr +* isindir +* idirouhab +* ismferd +* enver +* diclophis +* jeffdesc +* costimuraru +* verwilst +* ezelenka diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/Chart.yaml new file mode 100644 index 000000000..b65ac15d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +- name: kang-makes + url: https://github.com/kang-makes +name: common-library +type: library +version: 1.2.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/DEVELOPERS.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/DEVELOPERS.md new file mode 100644 index 000000000..3ccc108e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/DEVELOPERS.md @@ -0,0 +1,663 @@ +# Functions/templates documented for chart writers +Here is some rough documentation separated by the file that contains the function, the function +name and how to use it. We are not covering functions that start with `_` (e.g. +`newrelic.common.license._licenseKey`) because they are used internally by this library for +other helpers. Helm does not have the concept of "public" or "private" functions/templates so +this is a convention of ours. + +## _naming.tpl +These functions are used to name objects. + +### `newrelic.common.naming.name` +This is the same as the idiomatic `CHART-NAME.name` that is created when you use `helm create`. + +It honors `.Values.nameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.name" . }} +``` + +### `newrelic.common.naming.fullname` +This is the same as the idiomatic `CHART-NAME.fullname` that is created when you use `helm create` + +It honors `.Values.fullnameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.fullname" . }} +``` + +### `newrelic.common.naming.chart` +This is the same as the idiomatic `CHART-NAME.chart` that is created when you use `helm create`. + +It is mostly useless for chart writers. It is used internally for templating the labels but there +is no reason to keep it "private". + +Usage: +```mustache +{{ include "newrelic.common.naming.chart" . }} +``` + +### `newrelic.common.naming.truncateToDNS` +This is a useful template that could be used to trim a string to 63 chars and does not end with a dash (`-`). +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $truncatedName := include "newrelic.common.naming.truncateToDNS" $nameToTruncate }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-string-that-should-be */ -}} +``` + +### `newrelic.common.naming.truncateToDNSWithSuffix` +This template function is the same as the above but instead of receiving a string you should give a `dict` +with a `name` and a `suffix`. This function will join them with a dash (`-`) and trim the `name` so the +result of `name-suffix` is no more than 63 chars + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $suffix := "A-NOT-SO-LONG-SUFFIX" }} +{{- $truncatedName := include "truncateToDNSWithSuffix" (dict "name" $nameToTruncate "suffix" $suffix) }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-A-NOT-SO-LONG-SUFFIX */ -}} +``` + + + +## _labels.tpl +### `newrelic.common.labels`, `newrelic.common.labels.selectorLabels` and `newrelic.common.labels.podLabels` +These are functions that are used to label objects. They are configured by this `values.yaml` +```yaml +global: + podLabels: {} # included in all the pods of all the charts that implement this library + labels: {} # included in all the objects of all the charts that implement this library +podLabels: {} # included in all the pods of this chart +labels: {} # included in all the objects of this chart +``` + +label maps are merged from global to local values. + +And chart writer should use them like this: +```mustache +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} +``` + +`newrelic.common.labels.podLabels` includes `newrelic.common.labels.selectorLabels` automatically. + + + +## _priority-class-name.tpl +### `newrelic.common.priorityClassName` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + priorityClassName: "" +priorityClassName: "" +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `priorityClassName` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} +``` + + + +## _hostnetwork.tpl +### `newrelic.common.hostNetwork` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + hostNetwork: # Note that this is empty (nil) +hostNetwork: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `hostNetwork` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.hostNetwork" . }} + hostNetwork: {{ . }} + {{- end }} +``` + +### `newrelic.common.hostNetwork.value` +This function is an abstraction of the function above but this returns directly "true" or "false". + +Be careful with using this with an `if` as Helm does evaluate "false" (string) as `true`. + +Usage (example in a pod spec): +```mustache +spec: + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} +``` + + + +## _dnsconfig.tpl +### `newrelic.common.dnsConfig` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + dnsConfig: {} +dnsConfig: {} +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `dnsConfig` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _images.tpl +These functions help us to deal with how images are templated. This allows setting `registries` +where to fetch images globally while being flexible enough to fit in different maps of images +and deployments with one or more images. This is the example of a complex `values.yaml` that +we are going to use during the documentation of these functions: + +```yaml +global: + images: + registry: nexus-3-instance.internal.clients-domain.tld +jobImage: + registry: # defaults to "example.tld" when empty in these examples + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent + pullSecrets: [] +images: + integration: + registry: + repository: newrelic/nri-kube-events + tag: 1.8.0 + pullPolicy: IfNotPresent + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.22.0 + pullPolicy: IfNotPresent + pullSecrets: [] +``` + +### `newrelic.common.images.image` +This will return a string with the image ready to be downloaded that includes the registry, the image and the tag. +`defaultRegistry` is used to keep `registry` field empty in `values.yaml` so you can override the image using +`global.images.registry`, your local `jobImage.registry` and be able to fallback to a registry that is not `docker.io` +(Or the default repository that the client could have set in the CRI). + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.image" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.registry` +It returns the registry from the global or local values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.registry" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.repository` +It returns the image from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.tag` +It returns the image's tag from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.renderPullSecrets` +If returns a merged map that contains the pull secrets from the global configuration and the local one. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.jobImage.pullSecrets "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +``` + + + +## _serviceaccount.tpl +These functions are used to evaluate if the service account should be created, with which name and add annotations to it. + +The functions that the common library has implemented for service accounts are: +* `newrelic.common.serviceAccount.create` +* `newrelic.common.serviceAccount.name` +* `newrelic.common.serviceAccount.annotations` + +Usage: +```mustache +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +``` + + + +## _affinity.tpl, _nodeselector.tpl and _tolerations.tpl +These three files are almost the same and they follow the idiomatic way of `helm create`. + +Each function also looks if there is a global value like the other helpers. +```yaml +global: + affinity: {} + nodeSelector: {} + tolerations: [] +affinity: {} +nodeSelector: {} +tolerations: [] +``` + +The values here are replaced instead of be merged. If a value at root level is found, the global one is ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _agent-config.tpl +### `newrelic.common.agentConfig.defaults` +This returns a YAML that the agent can use directly as a config that includes other options from the values file like verbose mode, +custom attributes, FedRAMP and such. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include newrelic.common.naming.truncateToDNSWithSuffix (dict "name" (include "newrelic.common.naming.fullname" .) suffix "agent-config") }} + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "newrelic.common.agentConfig.defaults" . | nindent 4 }} +``` + + + +## _cluster.tpl +### `newrelic.common.cluster` +Returns the cluster name + +Usage: +```mustache +{{ include "newrelic.common.cluster" . }} +``` + + + +## _custom-attributes.tpl +### `newrelic.common.customAttributes` +Return custom attributes in YAML format. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + name: example +data: + custom-attributes.yaml: | + {{- include "newrelic.common.customAttributes" . | nindent 4 }} + custom-attributes.json: | + {{- include "newrelic.common.customAttributes" . | fromYaml | toJson | nindent 4 }} +``` + + + +## _fedramp.tpl +### `newrelic.common.fedramp.enabled` +Returns true if FedRAMP is enabled or an empty string if not. It can be safely used in conditionals as an empty string is a Helm falsiness. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled" . }} +``` + +### `newrelic.common.fedramp.enabled.value` +Returns true if FedRAMP is enabled or false if not. This is to have the value of FedRAMP ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled.value" . }} +``` + + + +## _license.tpl +### `newrelic.common.license.secretName` and ### `newrelic.common.license.secretKeyName` +Returns the secret and key inside the secret where to read the license key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the license key. + +To create the secret use `newrelic.common.license.secret`. + +Usage: +```mustache +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + containers: + - name: agent + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} +``` + + + +## _license_secret.tpl +### `newrelic.common.license.secret` +This function templates the secret that is used by agents and integrations with the license Key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any license key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.license.secret" . -}} +``` + + + +## _insights.tpl +### `newrelic.common.insightsKey.secretName` and ### `newrelic.common.insightsKey.secretKeyName` +Returns the secret and key inside the secret where to read the insights key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the insights key. + +To create the secret use `newrelic.common.insightsKey.secret`. + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: statsd +spec: + containers: + - name: statsd + env: + - name: "INSIGHTS_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + key: {{ include "newrelic.common.insightsKey.secretKeyName" . }} +``` + + + +## _insights_secret.tpl +### `newrelic.common.insightsKey.secret` +This function templates the secret that is used by agents and integrations with the insights key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any insights key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.insightsKey.secret" . -}} +``` + + + +## _low-data-mode.tpl +### `newrelic.common.lowDataMode` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + lowDataMode: # Note that this is empty (nil) +lowDataMode: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `lowdataMode` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.lowDataMode" . }} +``` + + + +## _privileged.tpl +### `newrelic.common.privileged` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + privileged: # Note that this is empty (nil) +privileged: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `privileged` is defined, the global one is going to be always ignored. + +Chart writers could override this and put directly a `true` in the `values.yaml` to override the +default of the common library. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.privileged" . }} +``` + +### `newrelic.common.privileged.value` +Returns true if privileged mode is enabled or false if not. This is to have the value of privileged ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.privileged.value" . }} +``` + + + +## _proxy.tpl +### `newrelic.common.proxy` +Returns the proxy URL configured by the user. + +Usage: +```mustache +{{ include "newrelic.common.proxy" . }} +``` + + + +## _security-context.tpl +Use these functions to share the security context among all charts. Useful in clusters that have security enforcing not to +use the root user (like OpenShift) or users that have an admission webhooks. + +The functions are: +* `newrelic.common.securityContext.container` +* `newrelic.common.securityContext.pod` + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + spec: + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + containers: + - name: example + {{- with include "nriKubernetes.securityContext.container" . }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} +``` + + + +## _staging.tpl +### `newrelic.common.nrStaging` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + nrStaging: # Note that this is empty (nil) +nrStaging: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `nrStaging` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging" . }} +``` + +### `newrelic.common.nrStaging.value` +Returns true if staging is enabled or false if not. This is to have the staging value ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging.value" . }} +``` + + + +## _verbose-log.tpl +### `newrelic.common.verboseLog` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + verboseLog: # Note that this is empty (nil) +verboseLog: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `verboseLog` is defined, the global one is going to be always ignored. + +Usage: +```mustache +{{ include "newrelic.common.verboseLog" . }} +``` + +### `newrelic.common.verboseLog.valueAsBoolean` +Returns true if verbose is enabled or false if not. This is to have the verbose value ready to be templated as a boolean + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsBoolean" . }} +``` + +### `newrelic.common.verboseLog.valueAsInt` +Returns 1 if verbose is enabled or 0 if not. This is to have the verbose value ready to be templated as an integer + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsInt" . }} +``` diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/README.md new file mode 100644 index 000000000..10f08ca67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/README.md @@ -0,0 +1,106 @@ +# Helm Common library + +The common library is a way to unify the UX through all the Helm charts that implement it. + +The tooling suite that New Relic is huge and growing and this allows to set things globally +and locally for a single chart. + +## Documentation for chart writers + +If you are writing a chart that is going to use this library you can check the [developers guide](/library/common-library/DEVELOPERS.md) to see all +the functions/templates that we have implemented, what they do and how to use them. + +## Values managed globally + +We want to have a seamless experience through all the charts so we created this library that tries to standardize the behaviour +of all the charts. Sadly, because of the complexity of all these integrations, not all the charts behave exactly as expected. + +An example is `newrelic-infrastructure` that ignores `hostNetwork` in the control plane scraper because most of the users has the +control plane listening in the node to `localhost`. + +For each chart that has a special behavior (or further information of the behavior) there is a "chart particularities" section +in its README.md that explains which is the expected behavior. + +At the time of writing this, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this +library and honors global options as described in this document. + +Here is a list of global options: + +| Global keys | Local keys | Default | Merged[1](#values-managed-globally-1) | Description | +|-------------|------------|---------|--------------------------------------------------|-------------| +| global.cluster | cluster | `""` | | Name of the Kubernetes cluster monitored | +| global.licenseKey | licenseKey | `""` | | This set this license key to use | +| global.customSecretName | customSecretName | `""` | | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there | +| global.customSecretLicenseKey | customSecretLicenseKey | `""` | | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located | +| global.podLabels | podLabels | `{}` | yes | Additional labels for chart pods | +| global.labels | labels | `{}` | yes | Additional labels for chart objects | +| global.priorityClassName | priorityClassName | `""` | | Sets pod's priorityClassName | +| global.hostNetwork | hostNetwork | `false` | | Sets pod's hostNetwork | +| global.dnsConfig | dnsConfig | `{}` | | Sets pod's dnsConfig | +| global.images.registry | See [Further information](#values-managed-globally-2) | `""` | | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.images.pullSecrets | See [Further information](#values-managed-globally-2) | `[]` | yes | Set secrets to be able to fetch images | +| global.podSecurityContext | podSecurityContext | `{}` | | Sets security context (at pod level) | +| global.containerSecurityContext | containerSecurityContext | `{}` | | Sets security context (at container level) | +| global.affinity | affinity | `{}` | | Sets pod/node affinities | +| global.nodeSelector | nodeSelector | `{}` | | Sets pod's node selector | +| global.tolerations | tolerations | `[]` | | Sets pod's tolerations to node taints | +| global.serviceAccount.create | serviceAccount.create | `true` | | Configures if the service account should be created or not | +| global.serviceAccount.name | serviceAccount.name | name of the release | | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. | +| global.serviceAccount.annotations | serviceAccount.annotations | `{}` | yes | Add these annotations to the service account we create | +| global.customAttributes | customAttributes | `{}` | | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.fedramp | fedramp | `false` | | Enables FedRAMP | +| global.lowDataMode | lowDataMode | `false` | | Reduces number of metrics sent in order to reduce costs | +| global.privileged | privileged | Depends on the chart | | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | +| global.proxy | proxy | `""` | | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.nrStaging | nrStaging | `false` | | Send the metrics to the staging backend. Requires a valid staging license key | +| global.verboseLog | verboseLog | `false` | | Sets the debug/trace logs to this integration or all integrations if it is set globally | + +### Further information + +#### 1. Merged + +Merged means that the values from global are not replaced by the local ones. Think in this example: +```yaml +global: + labels: + global: global + hostNetwork: true + nodeSelector: + global: global + +labels: + local: local +nodeSelector: + local: local +hostNetwork: false +``` + +This values will template `hostNetwork` to `false`, a map of labels `{ "global": "global", "local": "local" }` and a `nodeSelector` with +`{ "local": "local" }`. + +As Helm by default merges all the maps it could be confusing that we have two behaviors (merging `labels` and replacing `nodeSelector`) +the `values` from global to local. This is the rationale behind this: +* `hostNetwork` is templated to `false` because is overriding the value defined globally. +* `labels` are merged because the user may want to label all the New Relic pods at once and label other solution pods differently for + clarity' sake. +* `nodeSelector` does not merge as `labels` because could make it harder to overwrite/delete a selector that comes from global because + of the logic that Helm follows merging maps. + + +#### 2. Fine grain registries + +Some charts only have 1 image while others that can have 2 or more images. The local path for the registry can change depending +on the chart itself. + +As this is mostly unique per helm chart, you should take a look to the chart's values table (or directly to the `values.yaml` file to see all the +images that you can change. + +This should only be needed if you have an advanced setup that forces you to have granularity enough to force a proxy/cache registry per integration. + + + +#### 3. Privileged mode + +By default, from the common library, the privileged mode is set to false. But most of the helm charts require this to be true to fetch more +metrics so could see a true in some charts. The consequences of the privileged mode differ from one chart to another so for each chart that +honors the privileged mode toggle should be a section in the README explaining which is the behavior with it enabled or disabled. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_affinity.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_affinity.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod affinity */ -}} +{{- define "newrelic.common.affinity" -}} + {{- if .Values.affinity -}} + {{- toYaml .Values.affinity -}} + {{- else if .Values.global -}} + {{- if .Values.global.affinity -}} + {{- toYaml .Values.global.affinity -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_agent-config.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..9c32861a0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,26 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +log: + level: trace +{{- end }} + +{{- if (include "newrelic.common.nrStaging" . ) }} +staging: true +{{- end }} + +{{- with include "newrelic.common.proxy" . }} +proxy: {{ . | quote }} +{{- end }} + +{{- with include "newrelic.common.fedramp.enabled" . }} +fedramp: {{ . }} +{{- end }} + +{{- with fromYaml ( include "newrelic.common.customAttributes" . ) }} +custom_attributes: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_cluster.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_cluster.tpl @@ -0,0 +1,15 @@ +{{/* +Return the cluster +*/}} +{{- define "newrelic.common.cluster" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.cluster -}} + {{- .Values.cluster -}} +{{- else if $global.cluster -}} + {{- $global.cluster -}} +{{- else -}} + {{ fail "There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required." }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_custom-attributes.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_custom-attributes.tpl @@ -0,0 +1,17 @@ +{{/* +This will render custom attributes as a YAML ready to be templated or be used with `fromYaml`. +*/}} +{{- define "newrelic.common.customAttributes" -}} +{{- $customAttributes := dict -}} + +{{- $global := index .Values "global" | default dict -}} +{{- if $global.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes $global.customAttributes -}} +{{- end -}} + +{{- if .Values.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes .Values.customAttributes -}} +{{- end -}} + +{{- toYaml $customAttributes -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_dnsconfig.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_dnsconfig.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod dnsConfig */ -}} +{{- define "newrelic.common.dnsConfig" -}} + {{- if .Values.dnsConfig -}} + {{- toYaml .Values.dnsConfig -}} + {{- else if .Values.global -}} + {{- if .Values.global.dnsConfig -}} + {{- toYaml .Values.global.dnsConfig -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_fedramp.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_fedramp.tpl @@ -0,0 +1,25 @@ +{{- /* Defines the fedRAMP flag */ -}} +{{- define "newrelic.common.fedramp.enabled" -}} + {{- if .Values.fedramp -}} + {{- if .Values.fedramp.enabled -}} + {{- .Values.fedramp.enabled -}} + {{- end -}} + {{- else if .Values.global -}} + {{- if .Values.global.fedramp -}} + {{- if .Values.global.fedramp.enabled -}} + {{- .Values.global.fedramp.enabled -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{- /* Return FedRAMP value directly ready to be templated */ -}} +{{- define "newrelic.common.fedramp.enabled.value" -}} +{{- if include "newrelic.common.fedramp.enabled" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_hostnetwork.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_hostnetwork.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the hostNetwork toggle. +This helper allows to override the global `.global.hostNetwork` with the value of `.hostNetwork`. +Returns "true" if `hostNetwork` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.hostNetwork" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- /* +`get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs + +We also want only to return when this is true, returning `false` here will template "false" (string) when doing +an `(include "newrelic.common.hostNetwork" .)`, which is not an "empty string" so it is `true` if it is used +as an evaluation somewhere else. +*/ -}} +{{- if get .Values "hostNetwork" | kindIs "bool" -}} + {{- if .Values.hostNetwork -}} + {{- .Values.hostNetwork -}} + {{- end -}} +{{- else if get $global "hostNetwork" | kindIs "bool" -}} + {{- if $global.hostNetwork -}} + {{- $global.hostNetwork -}} + {{- end -}} +{{- end -}} +{{- end -}} + + +{{- /* +Abstraction of the hostNetwork toggle. +This helper abstracts the function "newrelic.common.hostNetwork" to return true or false directly. +*/ -}} +{{- define "newrelic.common.hostNetwork.value" -}} +{{- if include "newrelic.common.hostNetwork" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_images.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..d4fb43290 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_images.tpl @@ -0,0 +1,94 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "defaultRegistry" .defaultRegistry "context" .context ) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic.common.images.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image registry +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} +{{- $globalRegistry := "" -}} +{{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- with .context.Values.global.images.registry -}} + {{- $globalRegistry = . -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- $localRegistry := "" -}} +{{- if .imageRoot.registry -}} + {{- $localRegistry = .imageRoot.registry -}} +{{- end -}} + +{{- $registry := $localRegistry | default $globalRegistry | default .defaultRegistry -}} +{{- if $registry -}} + {{- $registry -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image repository +{{ include "newrelic.common.images.repository" .Values.path.to.the.image }} +*/ -}} +{{- define "newrelic.common.images.repository" -}} + {{- .repository -}} +{{- end -}} + + + +{{- /* +Return the proper image tag +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.tag" -}} + {{- .imageRoot.tag | default .context.Chart.AppVersion | toString -}} +{{- end -}} + + + +{{- /* +Return the proper Image Pull Registry Secret Names evaluating values as templates +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.path.to.the.images.pullSecrets1, .Values.path.to.the.images.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- if .context.Values.global.images.pullSecrets -}} + {{- range .context.Values.global.images.pullSecrets -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- range .pullSecrets -}} + {{- if not (empty .) -}} + {{- range . -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if $flatlist -}} + {{- toYaml $flatlist -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_insights.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_insights.tpl new file mode 100644 index 000000000..895c37732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_insights.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the Insights Key. +*/}} +{{- define "newrelic.common.insightsKey.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "insightskey" ) -}} +{{- include "newrelic.common.insightsKey._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +*/}} +{{- define "newrelic.common.insightsKey.secretKeyName" -}} +{{- include "newrelic.common.insightsKey._customSecretKey" . | default "insightsKey" -}} +{{- end -}} + +{{/* +Return local insightsKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._licenseKey" -}} +{{- if .Values.insightsKey -}} + {{- .Values.insightsKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.insightsKey -}} + {{- .Values.global.insightsKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the Insights Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretName" -}} +{{- if .Values.customInsightsKeySecretName -}} + {{- .Values.customInsightsKeySecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretName -}} + {{- .Values.global.customInsightsKeySecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretKey" -}} +{{- if .Values.customInsightsKeySecretKey -}} + {{- .Values.customInsightsKeySecretKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretKey }} + {{- .Values.global.customInsightsKeySecretKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_insights_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_insights_secret.yaml.tpl new file mode 100644 index 000000000..556caa6ca --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_insights_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the insights key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.insightsKey.secret" }} +{{- if not (include "newrelic.common.insightsKey._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.insightsKey._licenseKey" .) }} + {{- fail "You must specify a insightsKey or a customInsightsSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.insightsKey.secretKeyName" . }}: {{ include "newrelic.common.insightsKey._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_labels.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_labels.tpl @@ -0,0 +1,54 @@ +{{/* +This will render the labels that should be used in all the manifests used by the helm chart. +*/}} +{{- define "newrelic.common.labels" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- $chart := dict "helm.sh/chart" (include "newrelic.common.naming.chart" . ) -}} +{{- $managedBy := dict "app.kubernetes.io/managed-by" .Release.Service -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $labels := mustMergeOverwrite $chart $managedBy $selectorLabels -}} +{{- if .Chart.AppVersion -}} +{{- $labels = mustMergeOverwrite $labels (dict "app.kubernetes.io/version" .Chart.AppVersion) -}} +{{- end -}} + +{{- $globalUserLabels := $global.labels | default dict -}} +{{- $localUserLabels := .Values.labels | default dict -}} + +{{- $labels = mustMergeOverwrite $labels $globalUserLabels $localUserLabels -}} + +{{- toYaml $labels -}} +{{- end -}} + + + +{{/* +This will render the labels that should be used in deployments/daemonsets template pods as a selector. +*/}} +{{- define "newrelic.common.labels.selectorLabels" -}} +{{- $name := dict "app.kubernetes.io/name" ( include "newrelic.common.naming.name" . ) -}} +{{- $instance := dict "app.kubernetes.io/instance" .Release.Name -}} + +{{- $selectorLabels := mustMergeOverwrite $name $instance -}} + +{{- toYaml $selectorLabels -}} +{{- end }} + + + +{{/* +Pod labels +*/}} +{{- define "newrelic.common.labels.podLabels" -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $global := index .Values "global" | default dict -}} +{{- $globalPodLabels := $global.podLabels | default dict }} + +{{- $localPodLabels := .Values.podLabels | default dict }} + +{{- $podLabels := mustMergeOverwrite $selectorLabels $globalPodLabels $localPodLabels -}} + +{{- toYaml $podLabels -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_license.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..647b4ff43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_license.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "license" ) -}} +{{- include "newrelic.common.license._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +*/}} +{{- define "newrelic.common.license.secretKeyName" -}} +{{- include "newrelic.common.license._customSecretKey" . | default "licenseKey" -}} +{{- end -}} + +{{/* +Return local licenseKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._licenseKey" -}} +{{- if .Values.licenseKey -}} + {{- .Values.licenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.licenseKey -}} + {{- .Values.global.licenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the License Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretName" -}} +{{- if .Values.customSecretName -}} + {{- .Values.customSecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretName -}} + {{- .Values.global.customSecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretKey" -}} +{{- if .Values.customSecretLicenseKey -}} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_license_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_license_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the license key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.license.secret" }} +{{- if not (include "newrelic.common.license._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.license._licenseKey" .) }} + {{- fail "You must specify a licenseKey or a customSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.license.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.license.secretKeyName" . }}: {{ include "newrelic.common.license._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_low-data-mode.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_low-data-mode.tpl @@ -0,0 +1,26 @@ +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..19fa92648 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_naming.tpl @@ -0,0 +1,73 @@ +{{/* +This is an function to be called directly with a string just to truncate strings to +63 chars because some Kubernetes name fields are limited to that. +*/}} +{{- define "newrelic.common.naming.truncateToDNS" -}} +{{- . | trunc 63 | trimSuffix "-" }} +{{- end }} + + + +{{- /* +Given a name and a suffix returns a 'DNS Valid' which always include the suffix, truncating the name if needed. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If suffix is too long it gets truncated but it always takes precedence over name, so a 63 chars suffix would suppress the name. +Usage: +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "" "suffix" "my-suffix" ) }} +*/ -}} +{{- define "newrelic.common.naming.truncateToDNSWithSuffix" -}} +{{- $suffix := (include "newrelic.common.naming.truncateToDNS" .suffix) -}} +{{- $maxLen := (max (sub 63 (add1 (len $suffix))) 0) -}} {{- /* We prepend "-" to the suffix so an additional character is needed */ -}} + +{{- $newName := .name | trunc ($maxLen | int) | trimSuffix "-" -}} +{{- if $newName -}} +{{- printf "%s-%s" $newName $suffix -}} +{{- else -}} +{{ $suffix }} +{{- end -}} + +{{- end -}} + + + +{{/* +Expand the name of the chart. +Uses the Chart name by default if nameOverride is not set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.name" -}} +{{- $name := .Values.nameOverride | default .Chart.Name -}} +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end }} + + + +{{/* +Create a default fully qualified app name. +By default the full name will be "" just in if it has the chart name included in that, if not +it will be concatenated like "-". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.fullname" -}} +{{- $name := include "newrelic.common.naming.name" . -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} + +{{- end -}} + + + +{{/* +Create chart name and version as used by the chart label. +This function should not be used for naming objects. Use "common.naming.{name,fullname}" instead. +*/}} +{{- define "newrelic.common.naming.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_nodeselector.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_nodeselector.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod nodeSelector */ -}} +{{- define "newrelic.common.nodeSelector" -}} + {{- if .Values.nodeSelector -}} + {{- toYaml .Values.nodeSelector -}} + {{- else if .Values.global -}} + {{- if .Values.global.nodeSelector -}} + {{- toYaml .Values.global.nodeSelector -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_priority-class-name.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_priority-class-name.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the pod priorityClassName */ -}} +{{- define "newrelic.common.priorityClassName" -}} + {{- if .Values.priorityClassName -}} + {{- .Values.priorityClassName -}} + {{- else if .Values.global -}} + {{- if .Values.global.priorityClassName -}} + {{- .Values.global.priorityClassName -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_privileged.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_privileged.tpl @@ -0,0 +1,28 @@ +{{- /* +This is a helper that returns whether the chart should assume the user is fine deploying privileged pods. +*/ -}} +{{- define "newrelic.common.privileged" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists. */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values "privileged" | kindIs "bool" -}} + {{- if .Values.privileged -}} + {{- .Values.privileged -}} + {{- end -}} +{{- else if get $global "privileged" | kindIs "bool" -}} + {{- if $global.privileged -}} + {{- $global.privileged -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* Return directly "true" or "false" based in the exist of "newrelic.common.privileged" */ -}} +{{- define "newrelic.common.privileged.value" -}} +{{- if include "newrelic.common.privileged" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_proxy.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_proxy.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the proxy */ -}} +{{- define "newrelic.common.proxy" -}} + {{- if .Values.proxy -}} + {{- .Values.proxy -}} + {{- else if .Values.global -}} + {{- if .Values.global.proxy -}} + {{- .Values.global.proxy -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_security-context.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_security-context.tpl @@ -0,0 +1,23 @@ +{{- /* Defines the container securityContext context */ -}} +{{- define "newrelic.common.securityContext.container" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.containerSecurityContext -}} + {{- toYaml .Values.containerSecurityContext -}} +{{- else if $global.containerSecurityContext -}} + {{- toYaml $global.containerSecurityContext -}} +{{- end -}} +{{- end -}} + + + +{{- /* Defines the pod securityContext context */ -}} +{{- define "newrelic.common.securityContext.pod" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.podSecurityContext -}} + {{- toYaml .Values.podSecurityContext -}} +{{- else if $global.podSecurityContext -}} + {{- toYaml $global.podSecurityContext -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_serviceaccount.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..2d352f6ea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_serviceaccount.tpl @@ -0,0 +1,90 @@ +{{- /* Defines if the service account has to be created or not */ -}} +{{- define "newrelic.common.serviceAccount.create" -}} +{{- $valueFound := false -}} + +{{- /* Look for a global creation of a service account */ -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "create" | kindIs "bool") -}} + {{- $valueFound = true -}} + {{- if .Values.serviceAccount.create -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.serviceAccount.name" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.serviceAccount.create -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Look for a local creation of a service account */ -}} +{{- if not $valueFound -}} + {{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} + {{- $global := index .Values "global" | default dict -}} + {{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "create" | kindIs "bool" -}} + {{- $valueFound = true -}} + {{- if $global.serviceAccount.create -}} + {{- $global.serviceAccount.create -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* In case no serviceAccount value has been found, default to "true" */ -}} +{{- if not $valueFound -}} +true +{{- end -}} +{{- end -}} + + + +{{- /* Defines the name of the service account */ -}} +{{- define "newrelic.common.serviceAccount.name" -}} +{{- $localServiceAccount := "" -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "name" | kindIs "string") -}} + {{- $localServiceAccount = .Values.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := "" -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "name" | kindIs "string" -}} + {{- $globalServiceAccount = $global.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- if (include "newrelic.common.serviceAccount.create" .) -}} + {{- $localServiceAccount | default $globalServiceAccount | default (include "newrelic.common.naming.fullname" .) -}} +{{- else -}} + {{- $localServiceAccount | default $globalServiceAccount | default "default" -}} +{{- end -}} +{{- end -}} + + + +{{- /* Merge the global and local annotations for the service account */ -}} +{{- define "newrelic.common.serviceAccount.annotations" -}} +{{- $localServiceAccount := dict -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if get .Values.serviceAccount "annotations" -}} + {{- $localServiceAccount = .Values.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := dict -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "annotations" -}} + {{- $globalServiceAccount = $global.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $merged := mustMergeOverwrite $globalServiceAccount $localServiceAccount -}} + +{{- if $merged -}} + {{- toYaml $merged -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_staging.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_staging.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the nrStaging toggle. +This helper allows to override the global `.global.nrStaging` with the value of `.nrStaging`. +Returns "true" if `nrStaging` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.nrStaging" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "nrStaging" | kindIs "bool") -}} + {{- if .Values.nrStaging -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.nrStaging" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.nrStaging -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "nrStaging" | kindIs "bool" -}} + {{- if $global.nrStaging -}} + {{- $global.nrStaging -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Returns "true" of "false" directly instead of empty string (Helm falsiness) based on the exit of "newrelic.common.nrStaging" +*/ -}} +{{- define "newrelic.common.nrStaging.value" -}} +{{- if include "newrelic.common.nrStaging" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_tolerations.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_tolerations.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod tolerations */ -}} +{{- define "newrelic.common.tolerations" -}} + {{- if .Values.tolerations -}} + {{- toYaml .Values.tolerations -}} + {{- else if .Values.global -}} + {{- if .Values.global.tolerations -}} + {{- toYaml .Values.global.tolerations -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_verbose-log.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/templates/_verbose-log.tpl @@ -0,0 +1,54 @@ +{{- /* +Abstraction of the verbose toggle. +This helper allows to override the global `.global.verboseLog` with the value of `.verboseLog`. +Returns "true" if `verbose` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.verboseLog" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "verboseLog" | kindIs "bool") -}} + {{- if .Values.verboseLog -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.verboseLog" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.verboseLog -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "verboseLog" | kindIs "bool" -}} + {{- if $global.verboseLog -}} + {{- $global.verboseLog -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return true or false directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsBoolean" -}} +{{- if include "newrelic.common.verboseLog" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return 1 or 0 directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsInt" -}} +{{- if include "newrelic.common.verboseLog" . -}} +1 +{{- else -}} +0 +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/charts/common-library/values.yaml @@ -0,0 +1 @@ +# values are not needed for the library chart, however this file is still needed for helm lint to work. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/ci/test-cplane-kind-deployment-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/ci/test-cplane-kind-deployment-values.yaml new file mode 100644 index 000000000..1e2c36d21 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/ci/test-cplane-kind-deployment-values.yaml @@ -0,0 +1,135 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + +common: + agentConfig: + # We set it in order for the kubelet to not crash when posting tho the agent. Since the License_Key is + # not valid, the Identity Api doesn't return an AgentID and the server from the Agent takes to long to respond + is_forward_only: true + config: + sink: + http: + timeout: 180s + +customAttributes: + new: relic + loren: ipsum + +# Disable KSM scraper as it is not enabled when testing this chart individually. +ksm: + enabled: false + +# K8s DaemonSets update strategy. +updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + +enableProcessMetrics: "false" +serviceAccount: + create: true + +podAnnotations: + annotation1: "annotation" +podLabels: + label1: "label" + +securityContext: + runAsUser: 1000 + runAsGroup: 2000 + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + +privileged: true + +rbac: + create: true + pspEnabled: false + +prefixDisplayNameWithCluster: false +useNodeNameAsDisplayName: true +integrations_config: [] + +kubelet: + enabled: true + annotations: {} + tolerations: + - operator: "Exists" + effect: "NoSchedule" + - operator: "Exists" + effect: "NoExecute" + extraEnv: + - name: ENV_VAR1 + value: "var1" + - name: ENV_VAR2 + value: "var2" + resources: + limits: + memory: 400M + requests: + cpu: 100m + memory: 180M + config: + scheme: "http" + +controlPlane: + kind: Deployment + enabled: true + config: + etcd: + enabled: true + autodiscover: + - selector: "tier=control-plane,component=etcd" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:4001 + insecureSkipVerify: true + auth: + type: bearer + - url: http://localhost:2381 + scheduler: + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-scheduler" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10259 + insecureSkipVerify: true + auth: + type: bearer + controllerManager: + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-controller-manager" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10257 + insecureSkipVerify: true + auth: + type: bearer + mtls: + secretName: secret-name + secretNamespace: default + apiServer: + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-apiserver" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:8443 + insecureSkipVerify: true + auth: + type: bearer + mtls: + secretName: secret-name4 + - url: http://localhost:8080 + +images: + integration: + tag: test + repository: e2e/nri-kubernetes diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/ci/test-values.yaml new file mode 100644 index 000000000..125a49607 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/ci/test-values.yaml @@ -0,0 +1,134 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + +common: + agentConfig: + # We set it in order for the kubelet to not crash when posting tho the agent. Since the License_Key is + # not valid, the Identity Api doesn't return an AgentID and the server from the Agent takes to long to respond + is_forward_only: true + config: + sink: + http: + timeout: 180s + +customAttributes: + new: relic + loren: ipsum + +# Disable KSM scraper as it is not enabled when testing this chart individually. +ksm: + enabled: false + +# K8s DaemonSets update strategy. +updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + +enableProcessMetrics: "false" +serviceAccount: + create: true + +podAnnotations: + annotation1: "annotation" +podLabels: + label1: "label" + +securityContext: + runAsUser: 1000 + runAsGroup: 2000 + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + +privileged: true + +rbac: + create: true + pspEnabled: false + +prefixDisplayNameWithCluster: false +useNodeNameAsDisplayName: true +integrations_config: [] + +kubelet: + enabled: true + annotations: {} + tolerations: + - operator: "Exists" + effect: "NoSchedule" + - operator: "Exists" + effect: "NoExecute" + extraEnv: + - name: ENV_VAR1 + value: "var1" + - name: ENV_VAR2 + value: "var2" + resources: + limits: + memory: 400M + requests: + cpu: 100m + memory: 180M + config: + scheme: "http" + +controlPlane: + enabled: true + config: + etcd: + enabled: true + autodiscover: + - selector: "tier=control-plane,component=etcd" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:4001 + insecureSkipVerify: true + auth: + type: bearer + - url: http://localhost:2381 + scheduler: + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-scheduler" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10259 + insecureSkipVerify: true + auth: + type: bearer + controllerManager: + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-controller-manager" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10257 + insecureSkipVerify: true + auth: + type: bearer + mtls: + secretName: secret-name + secretNamespace: default + apiServer: + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-apiserver" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:8443 + insecureSkipVerify: true + auth: + type: bearer + mtls: + secretName: secret-name4 + - url: http://localhost:8080 + +images: + integration: + tag: test + repository: e2e/nri-kubernetes diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/NOTES.txt b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/NOTES.txt new file mode 100644 index 000000000..16cc6ea13 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/NOTES.txt @@ -0,0 +1,131 @@ +{{- if not .Values.forceUnsupportedInterval }} +{{- $max := 40 }} +{{- $min := 10 }} +{{- if not (.Values.common.config.interval | hasSuffix "s") }} +{{ fail (printf "Interval must be between %ds and %ds" $min $max ) }} +{{- end }} +{{- if gt ( .Values.common.config.interval | trimSuffix "s" | int64 ) $max }} +{{ fail (printf "Intervals larger than %ds are not supported" $max) }} +{{- end }} +{{- if lt ( .Values.common.config.interval | trimSuffix "s" | int64 ) $min }} +{{ fail (printf "Intervals smaller than %ds are not supported" $min) }} +{{- end }} +{{- end }} + +{{- if or (not .Values.ksm.enabled) (not .Values.kubelet.enabled) }} +Warning: +======== + +You have specified ksm or kubelet integration components as not enabled. +Those components are needed to have the full experience on NROne kubernetes explorer. +{{- end }} + +{{- if and .Values.controlPlane.enabled (not (include "nriKubernetes.controlPlane.hostNetwork" .)) }} +Warning: +======== + +Most Control Plane components listen in the loopback address only, which is not reachable without `hostNetwork: true`. +Control plane autodiscovery might not work as expected. +You can enable hostNetwork for all pods by setting `global.hotNetwork`, `hostNetwork` or only for the control +plane pods by setting `controlPlane.hostNetwork: true`. Alternatively, you can disable control plane monitoring altogether with +`controlPlane.enabled: false`. +{{- end }} + +{{- if and (include "newrelic.fargate" .) .Values.kubelet.affinity }} +Warning: +======== + +You have specified both an EKS Fargate environment (global.fargate) and custom +nodeAffinity rules, so we couldn't automatically exclude the kubelet daemonSet from +Fargate nodes. In order for the integration to work, you MUST manually exclude +the daemonSet from Fargate nodes. + +Please make sure your `values.yaml' contains a .kubelet.affinity.nodeAffinity that achieve the same effect as: + +affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: eks.amazonaws.com/compute-type + operator: NotIn + values: + - fargate +{{- end }} + +{{- if and .Values.nodeAffinity .Values.controlPlane.enabled }} +WARNING: `nodeAffinity` is deprecated +===================================== + +We have applied the old `nodeAffinity` to KSM and Kubelet components, but *NOT* to the control plane component as it +might conflict with the default nodeSelector. +This shimming will be removed in the future, please convert your `nodeAffinity` item into: +`ksm.affinity.nodeAffinity`, `controlPlane.affinity.nodeAffinity`, and `kubelet.affinity.nodeAffinity`. +{{- end }} + +{{- if and .Values.integrations_config }} +WARNING: `integrations_config` is deprecated +============================================ + +We have automatically translated `integrations_config` to the new format, but this shimming will be removed in the +future. Please migrate your configs to the new format in the `integrations` key. +{{- end }} + +{{- if or .Values.kubeStateMetricsScheme .Values.kubeStateMetricsPort .Values.kubeStateMetricsUrl .Values.kubeStateMetricsPodLabel .Values.kubeStateMetricsNamespace }} +WARNING: `kubeStateMetrics*` are deprecated +=========================================== + +We have automatically translated your `kubeStateMetrics*` values to the new format, but this shimming will be removed in +the future. Please migrate your configs to the new format in the `ksm.config` key. +{{- end }} + +{{- if .Values.runAsUser }} +WARNING: `runAsUser` is deprecated +================================== + +We have automatically translated your `runAsUser` setting to the new format, but this shimming will be removed in the +future. Please migrate your configs to the new format in the `securityContext` key. +{{- end }} + +{{- if .Values.config }} +WARNING: `config` is deprecated +=============================== + +We have automatically translated your `config` setting to the new format, but this shimming will be removed in the +future. Please migrate your agent config to the new format in the `common.agentConfig` key. +{{- end }} + + +{{ $errors:= "" }} + +{{- if .Values.logFile }} +{{ $errors = printf "%s\n\n%s" $errors (include "newrelic.compatibility.message.logFile" . ) }} +{{- end }} + +{{- if .Values.resources }} +{{ $errors = printf "%s\n\n%s" $errors (include "newrelic.compatibility.message.resources" . ) }} +{{- end }} + +{{- if .Values.image }} +{{ $errors = printf "%s\n\n%s" $errors (include "newrelic.compatibility.message.image" . ) }} +{{- end }} + +{{- if .Values.enableWindows }} +{{ $errors = printf "%s\n\n%s" $errors (include "newrelic.compatibility.message.windows" . ) }} +{{- end }} + +{{- if ( or .Values.controllerManagerEndpointUrl .Values.schedulerEndpointUrl .Values.etcdEndpointUrl .Values.apiServerEndpointUrl )}} +{{ $errors = printf "%s\n\n%s" $errors (include "newrelic.compatibility.message.apiURL" . ) }} +{{- end }} + +{{- if ( or .Values.etcdTlsSecretName .Values.etcdTlsSecretNamespace )}} +{{ $errors = printf "%s\n\n%s" $errors (include "newrelic.compatibility.message.etcdSecrets" . ) }} +{{- end }} + +{{- if .Values.apiServerSecurePort }} +{{ $errors = printf "%s\n\n%s" $errors (include "newrelic.compatibility.message.apiServerSecurePort" . ) }} +{{- end }} + +{{- if $errors | trim}} +{{- fail (printf "\n\n%s\n%s" (include "newrelic.compatibility.message.common" . ) $errors ) }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/_helpers.tpl new file mode 100644 index 000000000..033ef0bfc --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/_helpers.tpl @@ -0,0 +1,118 @@ +{{/* +Create a default fully qualified app name. + +This is a copy and paste from the common-library's name helper because the overriding system was broken. +As we have to change the logic to use "nrk8s" instead of `.Chart.Name` we need to maintain here a version +of the fullname helper + +By default the full name will be "" just in if it has "nrk8s" included in that, if not +it will be concatenated like "-nrk8s". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "nriKubernetes.naming.fullname" -}} +{{- $name := .Values.nameOverride | default "nrk8s" -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end -}} + + + +{{- /* Naming helpers*/ -}} +{{- define "nriKubernetes.naming.secrets" }} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "secrets") -}} +{{- end -}} + + + +{{- /* Return a YAML with the mode to be added to the labels */ -}} +{{- define "nriKubernetes._mode" -}} +{{- if include "newrelic.common.privileged" . -}} + mode: privileged +{{- else -}} + mode: unprivileged +{{- end -}} +{{- end -}} + + + +{{/* +Add `mode` label to the labels that come from the common library for all the objects +*/}} +{{- define "nriKubernetes.labels" -}} +{{- $labels := include "newrelic.common.labels" . | fromYaml -}} +{{- $mode := fromYaml ( include "nriKubernetes._mode" . ) -}} + +{{- mustMergeOverwrite $labels $mode | toYaml -}} +{{- end -}} + + + +{{/* +Add `mode` label to the labels that come from the common library for podLabels +*/}} +{{- define "nriKubernetes.labels.podLabels" -}} +{{- $labels := include "newrelic.common.labels.podLabels" . | fromYaml -}} +{{- $mode := fromYaml ( include "nriKubernetes._mode" . ) -}} + +{{- mustMergeOverwrite $labels $mode | toYaml -}} +{{- end -}} + + + +{{/* +Returns fargate +*/}} +{{- define "newrelic.fargate" -}} +{{- if .Values.fargate -}} + {{- .Values.fargate -}} +{{- else if .Values.global -}} + {{- if .Values.global.fargate -}} + {{- .Values.global.fargate -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- define "newrelic.integrationConfigDefaults" -}} +{{- if include "newrelic.common.lowDataMode" . -}} +interval: 30s +{{- else -}} +interval: 15s +{{- end -}} +{{- end -}} + + + +{{- /* These are the defaults that are used for all the containers in this chart (except the kubelet's agent */ -}} +{{- define "nriKubernetes.securityContext.containerDefaults" -}} +runAsUser: 1000 +runAsGroup: 2000 +allowPrivilegeEscalation: false +readOnlyRootFilesystem: true +{{- end -}} + + + +{{- /* Allow to change pod defaults dynamically based if we are running in privileged mode or not */ -}} +{{- define "nriKubernetes.securityContext.container" -}} +{{- $defaults := fromYaml ( include "nriKubernetes.securityContext.containerDefaults" . ) -}} +{{- $compatibilityLayer := include "newrelic.compatibility.securityContext" . | fromYaml -}} +{{- $commonLibrary := include "newrelic.common.securityContext.container" . | fromYaml -}} + +{{- $finalSecurityContext := dict -}} +{{- if $commonLibrary -}} + {{- $finalSecurityContext = mustMergeOverwrite $commonLibrary $compatibilityLayer -}} +{{- else -}} + {{- $finalSecurityContext = mustMergeOverwrite $defaults $compatibilityLayer -}} +{{- end -}} + +{{- toYaml $finalSecurityContext -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/_helpers_compatibility.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/_helpers_compatibility.tpl new file mode 100644 index 000000000..07365e5a1 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/_helpers_compatibility.tpl @@ -0,0 +1,202 @@ +{{/* +Returns true if .Values.ksm.enabled is true and the legacy disableKubeStateMetrics is not set +*/}} +{{- define "newrelic.compatibility.ksm.enabled" -}} +{{- if and .Values.ksm.enabled (not .Values.disableKubeStateMetrics) -}} +true +{{- end -}} +{{- end -}} + +{{/* +Returns legacy ksm values +*/}} +{{- define "newrelic.compatibility.ksm.legacyData" -}} +enabled: true +{{- if .Values.kubeStateMetricsScheme }} +scheme: {{ .Values.kubeStateMetricsScheme }} +{{- end -}} +{{- if .Values.kubeStateMetricsPort }} +port: {{ .Values.kubeStateMetricsPort }} +{{- end -}} +{{- if .Values.kubeStateMetricsUrl }} +staticURL: {{ .Values.kubeStateMetricsUrl }} +{{- end -}} +{{- if .Values.kubeStateMetricsPodLabel }} +selector: {{ printf "%s=kube-state-metrics" .Values.kubeStateMetricsPodLabel }} +{{- end -}} +{{- if .Values.kubeStateMetricsNamespace }} +namespace: {{ .Values.kubeStateMetricsNamespace}} +{{- end -}} +{{- end -}} + +{{/* +Returns the new value if available, otherwise falling back on the legacy one +*/}} +{{- define "newrelic.compatibility.valueWithFallback" -}} +{{- if .supported }} +{{- toYaml .supported}} +{{- else if .legacy -}} +{{- toYaml .legacy}} +{{- end }} +{{- end -}} + +{{/* +Returns a dictionary with legacy runAsUser config +*/}} +{{- define "newrelic.compatibility.securityContext" -}} +{{- if .Values.runAsUser -}} +{{ dict "runAsUser" .Values.runAsUser | toYaml }} +{{- end -}} +{{- end -}} + +{{/* +Returns legacy annotations if available +*/}} +{{- define "newrelic.compatibility.annotations" -}} +{{- with .Values.daemonSet -}} +{{- with .annotations -}} +{{- toYaml . }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Returns agent configmap merged with legacy config and legacy eventQueueDepth config +*/}} +{{- define "newrelic.compatibility.agentConfig" -}} +{{- $oldConfig := deepCopy (.Values.config | default dict) -}} +{{- $newConfig := deepCopy .Values.common.agentConfig -}} +{{- $eventQueueDepth := dict -}} + +{{- if .Values.eventQueueDepth -}} +{{- $eventQueueDepth = dict "event_queue_depth" .Values.eventQueueDepth -}} +{{- end -}} + +{{- mustMergeOverwrite $oldConfig $newConfig $eventQueueDepth | toYaml -}} +{{- end -}} + +{{- /* +Return a valid podSpec.affinity object from the old `.Values.nodeAffinity`. +*/ -}} +{{- define "newrelic.compatibility.nodeAffinity" -}} +{{- if .Values.nodeAffinity -}} +nodeAffinity: + {{- toYaml .Values.nodeAffinity | nindent 2 }} +{{- end -}} +{{- end -}} + +{{/* +Returns legacy integrations_config configmap data +*/}} +{{- define "newrelic.compatibility.integrations" -}} +{{- if .Values.integrations_config -}} +{{- range .Values.integrations_config }} +{{ .name -}}: |- + {{- toYaml .data | nindent 2 }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic.compatibility.message.logFile" -}} +The 'logFile' option is no longer supported and has been replaced by: + - common.agentConfig.log_file. + +------ +{{- end -}} + +{{- define "newrelic.compatibility.message.resources" -}} +You have specified the legacy 'resources' option in your values, which is not fully compatible with the v3 version. +This version deploys three different components and therefore you'll need to specify resources for each of them. +Please use + - ksm.resources, + - controlPlane.resources, + - kubelet.resources. + +------ +{{- end -}} + +{{- define "newrelic.compatibility.message.apiServerSecurePort" -}} +You have specified the legacy 'apiServerSecurePort' option in your values, which is not fully compatible with the v3 +version. +Please configure the API Server port as a part of 'apiServer.autodiscover[].endpoints' + +------ +{{- end -}} + +{{- define "newrelic.compatibility.message.windows" -}} +nri-kubernetes v3 does not support deploying into windows Nodes. +Please use the latest 2.x version of the chart. + +------ +{{- end -}} + +{{- define "newrelic.compatibility.message.etcdSecrets" -}} +Values "etcdTlsSecretName" and "etcdTlsSecretNamespace" are no longer supported, please specify them as a part of the +'etcd' config in the values, for example: + - endpoints: + - url: https://localhost:9979 + insecureSkipVerify: true + auth: + type: mTLS + mtls: + secretName: {{ .Values.etcdTlsSecretName | default "etcdTlsSecretName"}} + secretNamespace: {{ .Values.etcdTlsSecretNamespace | default "etcdTlsSecretNamespace"}} + +------ +{{- end -}} + +{{- define "newrelic.compatibility.message.apiURL" -}} +Values "controllerManagerEndpointUrl", "etcdEndpointUrl", "apiServerEndpointUrl", "schedulerEndpointUrl" are no longer +supported, please specify them as a part of the 'controlplane' config in the values, for example + autodiscover: + - selector: "tier=control-plane,component=etcd" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:4001 + insecureSkipVerify: true + auth: + type: bearer + +------ +{{- end -}} + +{{- define "newrelic.compatibility.message.image" -}} +Configuring image repository an tag under 'image' is no longer supported. +The following values are no longer supported and are currently ignored: + - image.repository + - image.tag + - image.pullPolicy + - image.pullSecrets + +Notice that the 3.x version of the integration uses 3 different images. +Please set: + - images.forwarder.* to configure the infrastructure-agent forwarder. + - images.agent.* to configure the image bundling the infrastructure-agent and on-host integrations. + - images.integration.* to configure the image in charge of scraping k8s data. + +------ +{{- end -}} + +{{- define "newrelic.compatibility.message.customAttributes" -}} +We still support using custom attributes but we support it as a map and dropped it as a string. +customAttributes: {{ .Values.customAttributes | quote }} + +You should change your values to something like this: + +customAttributes: +{{- range $k, $v := fromJson .Values.customAttributes -}} + {{- $k | nindent 2 }}: {{ $v | quote }} +{{- end }} + +**NOTE**: If you read above errors like "invalid character ':' after top-level value" or "json: cannot unmarshal string into Go value of type map[string]interface {}" means that the string you have in your values is not a valid JSON, Helm is not able to parse it and we could not show you how you should change it. Sorry. +{{- end -}} + +{{- define "newrelic.compatibility.message.common" -}} +###### +The chart cannot be rendered since the values listed below are not supported. Please replace those with the new ones compatible with newrelic-infrastructure V3. + +Keep in mind that the flag "--reuse-values" is not supported when migrating from V2 to V3. +Further information can be found in the official docs https://docs.newrelic.com/docs/kubernetes-pixie/kubernetes-integration/get-started/changes-since-v3#migration-guide" +###### +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/clusterrole.yaml new file mode 100644 index 000000000..391dc1e1f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/clusterrole.yaml @@ -0,0 +1,35 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.naming.fullname" . }} +rules: + - apiGroups: [""] + resources: + - "nodes/metrics" + - "nodes/stats" + - "nodes/proxy" + verbs: ["get", "list"] + - apiGroups: [ "" ] + resources: + - "endpoints" + - "services" + - "nodes" + - "namespaces" + - "pods" + verbs: [ "get", "list", "watch" ] + - nonResourceURLs: ["/metrics"] + verbs: ["get"] + {{- if .Values.rbac.pspEnabled }} + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + - privileged-{{ include "newrelic.common.naming.fullname" . }} + verbs: + - use + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..fc5dfb8da --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.naming.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic.common.naming.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_affinity_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_affinity_helper.tpl new file mode 100644 index 000000000..320d16dae --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_affinity_helper.tpl @@ -0,0 +1,11 @@ +{{- /* +As this chart deploys what it should be three charts to maintain the transition to v3 as smooth as possible. +This means that this chart has 3 affinity so a helper should be done per scraper. +*/ -}} +{{- define "nriKubernetes.controlPlane.affinity" -}} +{{- if .Values.controlPlane.affinity -}} + {{- toYaml .Values.controlPlane.affinity -}} +{{- else if include "newrelic.common.affinity" . -}} + {{- include "newrelic.common.affinity" . -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_agent-config_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_agent-config_helper.tpl new file mode 100644 index 000000000..e113def82 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_agent-config_helper.tpl @@ -0,0 +1,20 @@ +{{- /* +Defaults for controlPlane's agent config +*/ -}} +{{- define "nriKubernetes.controlPlane.agentConfig.defaults" -}} +is_forward_only: true +http_server_enabled: true +http_server_port: 8001 +{{- end -}} + + + +{{- define "nriKubernetes.controlPlane.agentConfig" -}} +{{- $agentDefaults := fromYaml ( include "newrelic.common.agentConfig.defaults" . ) -}} +{{- $controlPlane := fromYaml ( include "nriKubernetes.controlPlane.agentConfig.defaults" . ) -}} +{{- $agentConfig := fromYaml ( include "newrelic.compatibility.agentConfig" . ) -}} +{{- $cpAgentConfig := .Values.controlPlane.agentConfig -}} +{{- $customAttributes := dict "custom_attributes" (dict "clusterName" (include "newrelic.common.cluster" . )) -}} + +{{- mustMergeOverwrite $agentDefaults $controlPlane $agentConfig $cpAgentConfig $customAttributes | toYaml -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_host_network.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_host_network.tpl new file mode 100644 index 000000000..2f3bdf2d9 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_host_network.tpl @@ -0,0 +1,22 @@ +{{/* Returns whether the controlPlane scraper should run with hostNetwork: true based on the user configuration. */}} +{{- define "nriKubernetes.controlPlane.hostNetwork" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values.controlPlane "hostNetwork" | kindIs "bool" -}} + {{- if .Values.controlPlane.hostNetwork -}} + {{- .Values.controlPlane.hostNetwork -}} + {{- end -}} +{{- else if include "newrelic.common.hostNetwork" . -}} + {{- include "newrelic.common.hostNetwork" . -}} +{{- end -}} +{{- end -}} + + + +{{/* Abstraction of "nriKubernetes.controlPlane.hostNetwork" that returns true of false directly */}} +{{- define "nriKubernetes.controlPlane.hostNetwork.value" -}} +{{- if include "nriKubernetes.controlPlane.hostNetwork" . -}} + true +{{- else -}} + false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_naming.tpl new file mode 100644 index 000000000..4b9ef22e3 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_naming.tpl @@ -0,0 +1,16 @@ +{{- /* Naming helpers*/ -}} +{{- define "nriKubernetes.controlplane.fullname" -}} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "controlplane") -}} +{{- end -}} + +{{- define "nriKubernetes.controlplane.fullname.agent" -}} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "agent-controlplane") -}} +{{- end -}} + +{{- define "nriKubernetes.controlplane.fullname.serviceAccount" -}} +{{- if include "newrelic.common.serviceAccount.create" . -}} + {{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "controlplane") -}} +{{- else -}} + {{- include "newrelic.common.serviceAccount.name" . -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_rbac.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_rbac.tpl new file mode 100644 index 000000000..a279df6b4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_rbac.tpl @@ -0,0 +1,40 @@ +{{/* +Returns the list of namespaces where secrets need to be accessed by the controlPlane integration to do mTLS Auth +*/}} +{{- define "nriKubernetes.controlPlane.roleBindingNamespaces" -}} +{{ $namespaceList := list }} +{{- range $components := .Values.controlPlane.config }} + {{- if $components }} + {{- if kindIs "map" $components -}} + {{- if $components.staticEndpoint }} + {{- if $components.staticEndpoint.auth }} + {{- if $components.staticEndpoint.auth.mtls }} + {{- if $components.staticEndpoint.auth.mtls.secretNamespace }} + {{- $namespaceList = append $namespaceList $components.staticEndpoint.auth.mtls.secretNamespace -}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- if $components.autodiscover }} + {{- range $autodiscover := $components.autodiscover }} + {{- if $autodiscover }} + {{- if $autodiscover.endpoints }} + {{- range $endpoint := $autodiscover.endpoints }} + {{- if $endpoint.auth }} + {{- if $endpoint.auth.mtls }} + {{- if $endpoint.auth.mtls.secretNamespace }} + {{- $namespaceList = append $namespaceList $endpoint.auth.mtls.secretNamespace -}} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} +roleBindingNamespaces: + {{- uniq $namespaceList | toYaml | nindent 2 }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_tolerations_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_tolerations_helper.tpl new file mode 100644 index 000000000..3c82e82f5 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/_tolerations_helper.tpl @@ -0,0 +1,11 @@ +{{- /* +As this chart deploys what it should be three charts to maintain the transition to v3 as smooth as possible. +This means that this chart has 3 tolerations so a helper should be done per scraper. +*/ -}} +{{- define "nriKubernetes.controlPlane.tolerations" -}} +{{- if .Values.controlPlane.tolerations -}} + {{- toYaml .Values.controlPlane.tolerations -}} +{{- else if include "newrelic.common.tolerations" . -}} + {{- include "newrelic.common.tolerations" . -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/agent-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/agent-configmap.yaml new file mode 100644 index 000000000..77f2e11dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/agent-configmap.yaml @@ -0,0 +1,18 @@ +{{- if .Values.controlPlane.enabled -}} +{{- if .Values.customAttributes | kindIs "string" }} +{{- fail ( include "newrelic.compatibility.message.customAttributes" . ) -}} +{{- else -}} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.controlplane.fullname.agent" . }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "nriKubernetes.controlPlane.agentConfig" . | nindent 4 }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/clusterrole.yaml new file mode 100644 index 000000000..57633e7f7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/clusterrole.yaml @@ -0,0 +1,47 @@ +{{- if and (.Values.controlPlane.enabled) (.Values.rbac.create) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.controlplane.fullname" . }} +rules: + - apiGroups: [""] + resources: + - "nodes/metrics" + - "nodes/stats" + - "nodes/proxy" + verbs: ["get", "list"] + - apiGroups: [ "" ] + resources: + - "pods" + - "nodes" + verbs: [ "get", "list", "watch" ] + - nonResourceURLs: ["/metrics"] + verbs: ["get", "head"] + {{- if .Values.rbac.pspEnabled }} + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + - privileged-{{ include "newrelic.common.naming.fullname" . }} + verbs: + - use + {{- end -}} +{{- $namespaces := include "nriKubernetes.controlPlane.roleBindingNamespaces" . | fromYaml -}} +{{- if $namespaces.roleBindingNamespaces}} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.naming.secrets" . }} +rules: + - apiGroups: [""] + resources: + - "secrets" + verbs: ["get", "list", "watch"] +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/clusterrolebinding.yaml new file mode 100644 index 000000000..4e3530094 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if and (.Values.controlPlane.enabled) (.Values.rbac.create) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.controlplane.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "nriKubernetes.controlplane.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "nriKubernetes.controlplane.fullname.serviceAccount" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/daemonset.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/daemonset.yaml new file mode 100644 index 000000000..938fc48d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/daemonset.yaml @@ -0,0 +1,205 @@ +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: apps/v1 +kind: {{ .Values.controlPlane.kind }} +metadata: + namespace: {{ .Release.Namespace }} + labels: + {{- include "nriKubernetes.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.controlplane.fullname" . }} + {{- $legacyAnnotation:= fromYaml (include "newrelic.compatibility.annotations" .) -}} + {{- with include "newrelic.compatibility.valueWithFallback" (dict "legacy" $legacyAnnotation "supported" .Values.controlPlane.annotations )}} + annotations: {{ . | nindent 4 }} + {{- end }} +spec: + {{- if eq .Values.controlPlane.kind "DaemonSet"}} + {{- with .Values.updateStrategy }} + updateStrategy: {{ toYaml . | nindent 4 }} + {{- end }} + {{- end }} + {{- if eq .Values.controlPlane.kind "Deployment"}} + {{- with .Values.strategy }} + strategy: {{ toYaml . | nindent 4 }} + {{- end }} + {{- end }} + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: controlplane + template: + metadata: + annotations: + checksum/nri-kubernetes: {{ include (print $.Template.BasePath "/controlplane/scraper-configmap.yaml") . | sha256sum }} + checksum/agent-config: {{ include (print $.Template.BasePath "/controlplane/agent-configmap.yaml") . | sha256sum }} + {{- if include "newrelic.common.license.secret" . }}{{- /* If the is secret to template */}} + checksum/license-secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "nriKubernetes.labels.podLabels" . | nindent 8 }} + app.kubernetes.io/component: controlplane + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.images.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + hostNetwork: {{ include "nriKubernetes.controlPlane.hostNetwork.value" . }} + {{- if include "nriKubernetes.controlPlane.hostNetwork" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- end }} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "nriKubernetes.controlplane.fullname.serviceAccount" . }} + + {{- if .Values.controlPlane.initContainers }} + initContainers: {{- tpl (.Values.controlPlane.initContainers | toYaml) . | nindent 8 }} + {{- end }} + containers: + - name: controlplane + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} + imagePullPolicy: {{ .Values.images.integration.pullPolicy }} + {{- with include "nriKubernetes.securityContext.container" . | fromYaml }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + env: + - name: "NRI_KUBERNETES_SINK_HTTP_PORT" + value: {{ get (fromYaml (include "nriKubernetes.controlPlane.agentConfig" .)) "http_server_port" | quote }} + - name: "NRI_KUBERNETES_CLUSTERNAME" + value: {{ include "newrelic.common.cluster" . }} + - name: "NRI_KUBERNETES_VERBOSE" + value: {{ include "newrelic.common.verboseLog.valueAsBoolean" . | quote }} + + - name: "NRI_KUBERNETES_NODENAME" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + - name: "NRI_KUBERNETES_NODEIP" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "status.hostIP" + + {{- with .Values.controlPlane.extraEnv }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.controlPlane.extraEnvFrom }} + envFrom: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: nri-kubernetes-config + mountPath: /etc/newrelic-infra/nri-kubernetes.yml + subPath: nri-kubernetes.yml + {{- with .Values.controlPlane.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.controlPlane.resources }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + - name: forwarder + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.forwarder "context" .) }} + imagePullPolicy: {{ .Values.images.forwarder.pullPolicy }} + {{- with include "nriKubernetes.securityContext.container" . | fromYaml }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - containerPort: {{ get (fromYaml (include "nriKubernetes.controlPlane.agentConfig" .)) "http_server_port" }} + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} + + - name: "NRIA_DNS_HOSTNAME_RESOLUTION" + value: "false" + + - name: "K8S_NODE_NAME" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + + {{- if .Values.useNodeNameAsDisplayName }} + - name: "NRIA_DISPLAY_NAME" + {{- if .Values.prefixDisplayNameWithCluster }} + value: "{{ include "newrelic.common.cluster" . }}:$(K8S_NODE_NAME)" + {{- else }} + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + {{- end }} + {{- end }} + + {{- with .Values.controlPlane.extraEnv }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.controlPlane.extraEnvFrom }} + envFrom: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /var/db/newrelic-infra/data + name: forwarder-tmpfs-data + - mountPath: /var/db/newrelic-infra/user_data + name: forwarder-tmpfs-user-data + - mountPath: /tmp + name: forwarder-tmpfs-tmp + - name: config + mountPath: /etc/newrelic-infra.yml + subPath: newrelic-infra.yml + {{- with .Values.controlPlane.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.controlPlane.resources }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + volumes: + - name: nri-kubernetes-config + configMap: + name: {{ include "nriKubernetes.controlplane.fullname" . }} + items: + - key: nri-kubernetes.yml + path: nri-kubernetes.yml + - name: forwarder-tmpfs-data + emptyDir: {} + - name: forwarder-tmpfs-user-data + emptyDir: {} + - name: forwarder-tmpfs-tmp + emptyDir: {} + - name: config + configMap: + name: {{ include "nriKubernetes.controlplane.fullname.agent" . }} + items: + - key: newrelic-infra.yml + path: newrelic-infra.yml + {{- with .Values.controlPlane.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with include "nriKubernetes.controlPlane.affinity" . }} + affinity: + {{- . | nindent 8 }} + {{- end }} + {{- with include "nriKubernetes.controlPlane.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} + nodeSelector: + kubernetes.io/os: linux + {{- with .Values.controlPlane.nodeSelector | default (fromYaml (include "newrelic.common.nodeSelector" .)) }} + {{- toYaml . | nindent 8 }} + {{- end -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/rolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/rolebinding.yaml new file mode 100644 index 000000000..d97fc181a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/rolebinding.yaml @@ -0,0 +1,21 @@ +{{- if .Values.rbac.create }} +{{- $namespaces := (include "nriKubernetes.controlPlane.roleBindingNamespaces" . | fromYaml) -}} +{{- range $namespaces.roleBindingNamespaces }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + {{- include "newrelic.common.labels" $ | nindent 4 }} + name: {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" $) "suffix" .) }} + namespace: {{ . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "nriKubernetes.naming.secrets" $ }} +subjects: +- kind: ServiceAccount + name: {{ include "nriKubernetes.controlplane.fullname.serviceAccount" $ }} + namespace: {{ $.Release.Namespace }} +{{- end -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/scraper-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/scraper-configmap.yaml new file mode 100644 index 000000000..454665ded --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/scraper-configmap.yaml @@ -0,0 +1,36 @@ +{{- if .Values.controlPlane.enabled -}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.controlplane.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + nri-kubernetes.yml: |- + {{- (merge .Values.common.config (include "newrelic.integrationConfigDefaults" . | fromYaml)) | toYaml | nindent 4 }} + controlPlane: + {{- omit .Values.controlPlane.config "etcd" "scheduler" "controllerManager" "apiServer" | toYaml | nindent 6 }} + enabled: true + + {{- if .Values.controlPlane.config.etcd.enabled }} + etcd: + {{- toYaml .Values.controlPlane.config.etcd | nindent 8 -}} + {{- end -}} + + {{- if .Values.controlPlane.config.scheduler.enabled }} + scheduler: + {{- toYaml .Values.controlPlane.config.scheduler | nindent 8 -}} + {{- end -}} + + {{- if .Values.controlPlane.config.controllerManager.enabled }} + controllerManager: + {{- toYaml .Values.controlPlane.config.controllerManager | nindent 8 -}} + {{- end -}} + + {{- if .Values.controlPlane.config.apiServer.enabled }} + apiServer: + {{- toYaml .Values.controlPlane.config.apiServer | nindent 8 -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/serviceaccount.yaml new file mode 100644 index 000000000..502e1c986 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/controlplane/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.controlplane.fullname.serviceAccount" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_affinity_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_affinity_helper.tpl new file mode 100644 index 000000000..ce795708d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_affinity_helper.tpl @@ -0,0 +1,14 @@ +{{- /* +As this chart deploys what it should be three charts to maintain the transition to v3 as smooth as possible. +This means that this chart has 3 affinity so a helper should be done per scraper. +*/ -}} +{{- define "nriKubernetes.ksm.affinity" -}} +{{- if or .Values.ksm.affinity .Values.nodeAffinity -}} + {{- $legacyNodeAffinity := fromYaml ( include "newrelic.compatibility.nodeAffinity" . ) | default dict -}} + {{- $valuesAffinity := .Values.ksm.affinity | default dict -}} + {{- $affinity := mustMergeOverwrite $legacyNodeAffinity $valuesAffinity -}} + {{- toYaml $affinity -}} +{{- else if include "newrelic.common.affinity" . -}} + {{- include "newrelic.common.affinity" . -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_agent-config_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_agent-config_helper.tpl new file mode 100644 index 000000000..e7b55644c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_agent-config_helper.tpl @@ -0,0 +1,20 @@ +{{- /* +Defaults for ksm's agent config +*/ -}} +{{- define "nriKubernetes.ksm.agentConfig.defaults" -}} +is_forward_only: true +http_server_enabled: true +http_server_port: 8002 +{{- end -}} + + + +{{- define "nriKubernetes.ksm.agentConfig" -}} +{{- $agentDefaults := fromYaml ( include "newrelic.common.agentConfig.defaults" . ) -}} +{{- $ksm := fromYaml ( include "nriKubernetes.ksm.agentConfig.defaults" . ) -}} +{{- $agentConfig := fromYaml ( include "newrelic.compatibility.agentConfig" . ) -}} +{{- $ksmAgentConfig := .Values.ksm.agentConfig -}} +{{- $customAttributes := dict "custom_attributes" (dict "clusterName" (include "newrelic.common.cluster" . )) -}} + +{{- mustMergeOverwrite $agentDefaults $ksm $agentConfig $ksmAgentConfig $customAttributes | toYaml -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_host_network.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_host_network.tpl new file mode 100644 index 000000000..59a6db7be --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_host_network.tpl @@ -0,0 +1,22 @@ +{{/* Returns whether the ksm scraper should run with hostNetwork: true based on the user configuration. */}} +{{- define "nriKubernetes.ksm.hostNetwork" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values.ksm "hostNetwork" | kindIs "bool" -}} + {{- if .Values.ksm.hostNetwork -}} + {{- .Values.ksm.hostNetwork -}} + {{- end -}} +{{- else if include "newrelic.common.hostNetwork" . -}} + {{- include "newrelic.common.hostNetwork" . -}} +{{- end -}} +{{- end -}} + + + +{{/* Abstraction of "nriKubernetes.ksm.hostNetwork" that returns true of false directly */}} +{{- define "nriKubernetes.ksm.hostNetwork.value" -}} +{{- if include "nriKubernetes.ksm.hostNetwork" . -}} + true +{{- else -}} + false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_naming.tpl new file mode 100644 index 000000000..d8c283c43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_naming.tpl @@ -0,0 +1,8 @@ +{{- /* Naming helpers*/ -}} +{{- define "nriKubernetes.ksm.fullname" -}} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "ksm") -}} +{{- end -}} + +{{- define "nriKubernetes.ksm.fullname.agent" -}} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "agent-ksm") -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_tolerations_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_tolerations_helper.tpl new file mode 100644 index 000000000..e1a9fd80c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/_tolerations_helper.tpl @@ -0,0 +1,11 @@ +{{- /* +As this chart deploys what it should be three charts to maintain the transition to v3 as smooth as possible. +This means that this chart has 3 tolerations so a helper should be done per scraper. +*/ -}} +{{- define "nriKubernetes.ksm.tolerations" -}} +{{- if .Values.ksm.tolerations -}} + {{- toYaml .Values.ksm.tolerations -}} +{{- else if include "newrelic.common.tolerations" . -}} + {{- include "newrelic.common.tolerations" . -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/agent-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/agent-configmap.yaml new file mode 100644 index 000000000..6a438e9a3 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/agent-configmap.yaml @@ -0,0 +1,18 @@ +{{- if .Values.ksm.enabled -}} +{{- if .Values.customAttributes | kindIs "string" }} +{{- fail ( include "newrelic.compatibility.message.customAttributes" . ) -}} +{{- else -}} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.ksm.fullname.agent" . }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "nriKubernetes.ksm.agentConfig" . | nindent 4 }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/deployment.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/deployment.yaml new file mode 100644 index 000000000..507199d5a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/deployment.yaml @@ -0,0 +1,192 @@ +{{- if include "newrelic.compatibility.ksm.enabled" . -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: {{ .Release.Namespace }} + labels: + {{- include "nriKubernetes.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.ksm.fullname" . }} + {{- $legacyAnnotation:= fromYaml (include "newrelic.compatibility.annotations" .) -}} + {{- with include "newrelic.compatibility.valueWithFallback" (dict "legacy" $legacyAnnotation "supported" .Values.ksm.annotations )}} + annotations: {{ . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.strategy }} + strategy: {{ toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: ksm + template: + metadata: + annotations: + checksum/nri-kubernetes: {{ include (print $.Template.BasePath "/ksm/scraper-configmap.yaml") . | sha256sum }} + checksum/agent-config: {{ include (print $.Template.BasePath "/ksm/agent-configmap.yaml") . | sha256sum }} + {{- if include "newrelic.common.license.secret" . }}{{- /* If the is secret to template */}} + checksum/license-secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "nriKubernetes.labels.podLabels" . | nindent 8 }} + app.kubernetes.io/component: ksm + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.images.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} + hostNetwork: {{ include "nriKubernetes.ksm.hostNetwork.value" . }} + {{- if include "nriKubernetes.ksm.hostNetwork" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- end }} + + {{- if .Values.ksm.initContainers }} + initContainers: {{- tpl (.Values.ksm.initContainers | toYaml) . | nindent 8 }} + {{- end }} + containers: + - name: ksm + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} + imagePullPolicy: {{ .Values.images.integration.pullPolicy }} + {{- with include "nriKubernetes.securityContext.container" . | fromYaml }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + env: + - name: "NRI_KUBERNETES_SINK_HTTP_PORT" + value: {{ get (fromYaml (include "nriKubernetes.ksm.agentConfig" .)) "http_server_port" | quote }} + - name: "NRI_KUBERNETES_CLUSTERNAME" + value: {{ include "newrelic.common.cluster" . }} + - name: "NRI_KUBERNETES_VERBOSE" + value: {{ include "newrelic.common.verboseLog.valueAsBoolean" . | quote }} + + - name: "NRI_KUBERNETES_NODENAME" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + + {{- with .Values.ksm.extraEnv }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.ksm.extraEnvFrom }} + envFrom: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: nri-kubernetes-config + mountPath: /etc/newrelic-infra/nri-kubernetes.yml + subPath: nri-kubernetes.yml + {{- with .Values.ksm.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.ksm.resources }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + - name: forwarder + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.forwarder "context" .) }} + imagePullPolicy: {{ .Values.images.forwarder.pullPolicy }} + {{- with include "nriKubernetes.securityContext.container" . | fromYaml }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - containerPort: {{ get (fromYaml (include "nriKubernetes.ksm.agentConfig" .)) "http_server_port" }} + env: + - name: NRIA_LICENSE_KEY + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} + + - name: "NRIA_DNS_HOSTNAME_RESOLUTION" + value: "false" + + - name: "K8S_NODE_NAME" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + + {{- if .Values.useNodeNameAsDisplayName }} + - name: "NRIA_DISPLAY_NAME" + {{- if .Values.prefixDisplayNameWithCluster }} + value: "{{ include "newrelic.common.cluster" . }}:$(K8S_NODE_NAME)" + {{- else }} + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + {{- end }} + {{- end }} + + {{- with .Values.ksm.env }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.ksm.extraEnvFrom }} + envFrom: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /var/db/newrelic-infra/data + name: forwarder-tmpfs-data + - mountPath: /var/db/newrelic-infra/user_data + name: forwarder-tmpfs-user-data + - mountPath: /tmp + name: forwarder-tmpfs-tmp + - name: config + mountPath: /etc/newrelic-infra.yml + subPath: newrelic-infra.yml + {{- with .Values.ksm.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.ksm.resources }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + volumes: + - name: nri-kubernetes-config + configMap: + name: {{ include "nriKubernetes.ksm.fullname" . }} + items: + - key: nri-kubernetes.yml + path: nri-kubernetes.yml + - name: forwarder-tmpfs-data + emptyDir: {} + - name: forwarder-tmpfs-user-data + emptyDir: {} + - name: forwarder-tmpfs-tmp + emptyDir: {} + - name: config + configMap: + name: {{ include "nriKubernetes.ksm.fullname.agent" . }} + items: + - key: newrelic-infra.yml + path: newrelic-infra.yml + {{- with .Values.ksm.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with include "nriKubernetes.ksm.affinity" . }} + affinity: + {{- . | nindent 8 }} + {{- end }} + {{- with include "nriKubernetes.ksm.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} + nodeSelector: + kubernetes.io/os: linux + {{- with .Values.ksm.nodeSelector | default (fromYaml (include "newrelic.common.nodeSelector" .)) }} + {{- toYaml . | nindent 8 }} + {{- end -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/scraper-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/scraper-configmap.yaml new file mode 100644 index 000000000..3314df9c7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/ksm/scraper-configmap.yaml @@ -0,0 +1,15 @@ +{{- if include "newrelic.compatibility.ksm.enabled" . -}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.ksm.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + nri-kubernetes.yml: |- + {{- (merge .Values.common.config (include "newrelic.integrationConfigDefaults" . | fromYaml)) | toYaml | nindent 4 }} + ksm: + {{- mustMergeOverwrite .Values.ksm.config (include "newrelic.compatibility.ksm.legacyData" . | fromYaml) | toYaml | nindent 6 -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_affinity_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_affinity_helper.tpl new file mode 100644 index 000000000..a3abf0855 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_affinity_helper.tpl @@ -0,0 +1,33 @@ +{{- /* +Patch to add affinity in case we are running in fargate mode +*/ -}} +{{- define "nriKubernetes.kubelet.affinity.fargateDefaults" -}} +nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: eks.amazonaws.com/compute-type + operator: NotIn + values: + - fargate +{{- end -}} + + + +{{- /* +As this chart deploys what it should be three charts to maintain the transition to v3 as smooth as possible. +This means that this chart has 3 affinity so a helper should be done per scraper. +*/ -}} +{{- define "nriKubernetes.kubelet.affinity" -}} + +{{- if or .Values.kubelet.affinity .Values.nodeAffinity -}} + {{- $legacyNodeAffinity := fromYaml ( include "newrelic.compatibility.nodeAffinity" . ) | default dict -}} + {{- $valuesAffinity := .Values.kubelet.affinity | default dict -}} + {{- $affinity := mustMergeOverwrite $legacyNodeAffinity $valuesAffinity -}} + {{- toYaml $affinity -}} +{{- else if include "newrelic.common.affinity" . -}} + {{- include "newrelic.common.affinity" . -}} +{{- else if include "newrelic.fargate" . -}} + {{- include "nriKubernetes.kubelet.affinity.fargateDefaults" . -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_agent-config_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_agent-config_helper.tpl new file mode 100644 index 000000000..ea6ffc25f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_agent-config_helper.tpl @@ -0,0 +1,31 @@ +{{- /* +Defaults for kubelet's agent config +*/ -}} +{{- define "nriKubernetes.kubelet.agentConfig.defaults" -}} +http_server_enabled: true +http_server_port: 8003 +features: + docker_enabled: false +{{- if not ( include "newrelic.common.privileged" . ) }} +is_secure_forward_only: true +{{- end }} +{{- /* +`enableProcessMetrics` is commented in the values and we want to configure it when it is set to something +either `true` or `false`. So we test if the variable is a boolean and in that case simply use it. +*/}} +{{- if (get .Values "enableProcessMetrics" | kindIs "bool") }} +enable_process_metrics: {{ .Values.enableProcessMetrics }} +{{- end }} +{{- end -}} + + + +{{- define "nriKubernetes.kubelet.agentConfig" -}} +{{- $agentDefaults := fromYaml ( include "newrelic.common.agentConfig.defaults" . ) -}} +{{- $kubelet := fromYaml ( include "nriKubernetes.kubelet.agentConfig.defaults" . ) -}} +{{- $agentConfig := fromYaml ( include "newrelic.compatibility.agentConfig" . ) -}} +{{- $kubeletAgentConfig := .Values.kubelet.agentConfig -}} +{{- $customAttributes := dict "custom_attributes" (dict "clusterName" (include "newrelic.common.cluster" . )) -}} + +{{- mustMergeOverwrite $agentDefaults $kubelet $agentConfig $kubeletAgentConfig $customAttributes | toYaml -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_host_network.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_host_network.tpl new file mode 100644 index 000000000..7944f98a7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_host_network.tpl @@ -0,0 +1,22 @@ +{{/* Returns whether the kubelet scraper should run with hostNetwork: true based on the user configuration. */}} +{{- define "nriKubernetes.kubelet.hostNetwork" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values.kubelet "hostNetwork" | kindIs "bool" -}} + {{- if .Values.kubelet.hostNetwork -}} + {{- .Values.kubelet.hostNetwork -}} + {{- end -}} +{{- else if include "newrelic.common.hostNetwork" . -}} + {{- include "newrelic.common.hostNetwork" . -}} +{{- end -}} +{{- end -}} + + + +{{/* Abstraction of "nriKubernetes.kubelet.hostNetwork" that returns true of false directly */}} +{{- define "nriKubernetes.kubelet.hostNetwork.value" -}} +{{- if include "nriKubernetes.kubelet.hostNetwork" . -}} + true +{{- else -}} + false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_naming.tpl new file mode 100644 index 000000000..71c142156 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_naming.tpl @@ -0,0 +1,12 @@ +{{- /* Naming helpers*/ -}} +{{- define "nriKubernetes.kubelet.fullname" -}} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "kubelet") -}} +{{- end -}} + +{{- define "nriKubernetes.kubelet.fullname.agent" -}} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "agent-kubelet") -}} +{{- end -}} + +{{- define "nriKubernetes.kubelet.fullname.integrations" -}} +{{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "nriKubernetes.naming.fullname" .) "suffix" "integrations-cfg") -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_security_context_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_security_context_helper.tpl new file mode 100644 index 000000000..4e334466c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_security_context_helper.tpl @@ -0,0 +1,32 @@ +{{- /*This defines the defaults that the privileged mode has for the agent's securityContext */ -}} +{{- define "nriKubernetes.kubelet.securityContext.privileged" -}} +runAsUser: 0 +runAsGroup: 0 +allowPrivilegeEscalation: true +privileged: true +readOnlyRootFilesystem: true +{{- end -}} + + + +{{- /* This is the container security context for the agent */ -}} +{{- define "nriKubernetes.kubelet.securityContext.agentContainer" -}} +{{- $defaults := dict -}} +{{- if include "newrelic.common.privileged" . -}} +{{- $defaults = fromYaml ( include "nriKubernetes.kubelet.securityContext.privileged" . ) -}} +{{- else -}} +{{- $defaults = fromYaml ( include "nriKubernetes.securityContext.containerDefaults" . ) -}} +{{- end -}} + +{{- $compatibilityLayer := include "newrelic.compatibility.securityContext" . | fromYaml -}} +{{- $commonLibrary := include "newrelic.common.securityContext.container" . | fromYaml -}} + +{{- $finalSecurityContext := dict -}} +{{- if $commonLibrary -}} + {{- $finalSecurityContext = mustMergeOverwrite $commonLibrary $compatibilityLayer -}} +{{- else -}} + {{- $finalSecurityContext = mustMergeOverwrite $defaults $compatibilityLayer -}} +{{- end -}} + +{{- toYaml $finalSecurityContext -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_tolerations_helper.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_tolerations_helper.tpl new file mode 100644 index 000000000..e46d83d69 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/_tolerations_helper.tpl @@ -0,0 +1,11 @@ +{{- /* +As this chart deploys what it should be three charts to maintain the transition to v3 as smooth as possible. +This means that this chart has 3 tolerations so a helper should be done per scraper. +*/ -}} +{{- define "nriKubernetes.kubelet.tolerations" -}} +{{- if .Values.kubelet.tolerations -}} + {{- toYaml .Values.kubelet.tolerations -}} +{{- else if include "newrelic.common.tolerations" . -}} + {{- include "newrelic.common.tolerations" . -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/agent-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/agent-configmap.yaml new file mode 100644 index 000000000..0f71f129a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/agent-configmap.yaml @@ -0,0 +1,18 @@ +{{- if .Values.kubelet.enabled -}} +{{- if .Values.customAttributes | kindIs "string" }} +{{- fail ( include "newrelic.compatibility.message.customAttributes" . ) -}} +{{- else -}} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.kubelet.fullname.agent" . }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "nriKubernetes.kubelet.agentConfig" . | nindent 4 }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/daemonset.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/daemonset.yaml new file mode 100644 index 000000000..517079be7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/daemonset.yaml @@ -0,0 +1,265 @@ +{{- if (.Values.kubelet.enabled) }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + namespace: {{ .Release.Namespace }} + labels: + {{- include "nriKubernetes.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.kubelet.fullname" . }} + {{- $legacyAnnotation:= fromYaml (include "newrelic.compatibility.annotations" .) -}} + {{- with include "newrelic.compatibility.valueWithFallback" (dict "legacy" $legacyAnnotation "supported" .Values.kubelet.annotations )}} + annotations: {{ . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.updateStrategy }} + updateStrategy: {{ toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: kubelet + template: + metadata: + annotations: + checksum/nri-kubernetes: {{ include (print $.Template.BasePath "/kubelet/scraper-configmap.yaml") . | sha256sum }} + checksum/agent-config: {{ include (print $.Template.BasePath "/kubelet/agent-configmap.yaml") . | sha256sum }} + {{- if include "newrelic.common.license.secret" . }}{{- /* If the is secret to template */}} + checksum/license-secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- end }} + checksum/integrations_config: {{ include (print $.Template.BasePath "/kubelet/integrations-configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "nriKubernetes.labels.podLabels" . | nindent 8 }} + app.kubernetes.io/component: kubelet + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.images.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} + hostNetwork: {{ include "nriKubernetes.kubelet.hostNetwork.value" . }} + {{- if include "nriKubernetes.kubelet.hostNetwork" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- end }} + + {{- if .Values.kubelet.initContainers }} + initContainers: {{- tpl (.Values.kubelet.initContainers | toYaml) . | nindent 8 }} + {{- end }} + containers: + - name: kubelet + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} + imagePullPolicy: {{ .Values.images.integration.pullPolicy }} + {{- with include "nriKubernetes.securityContext.container" . | fromYaml }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + env: + - name: "NRI_KUBERNETES_SINK_HTTP_PORT" + value: {{ get (fromYaml (include "nriKubernetes.kubelet.agentConfig" .)) "http_server_port" | quote }} + - name: "NRI_KUBERNETES_CLUSTERNAME" + value: {{ include "newrelic.common.cluster" . }} + - name: "NRI_KUBERNETES_VERBOSE" + value: {{ include "newrelic.common.verboseLog.valueAsBoolean" . | quote }} + + - name: "NRI_KUBERNETES_NODENAME" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + # Required to connect to the kubelet + - name: "NRI_KUBERNETES_NODEIP" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "status.hostIP" + + {{- with .Values.kubelet.extraEnv }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.kubelet.extraEnvFrom }} + envFrom: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: nri-kubernetes-config + mountPath: /etc/newrelic-infra/nri-kubernetes.yml + subPath: nri-kubernetes.yml + {{- with .Values.kubelet.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.kubelet.resources }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + - name: agent + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} + args: [ "newrelic-infra" ] + imagePullPolicy: {{ .Values.images.agent.pullPolicy }} + {{- with include "nriKubernetes.kubelet.securityContext.agentContainer" . | fromYaml }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - containerPort: {{ get (fromYaml (include "nriKubernetes.kubelet.agentConfig" .)) "http_server_port" }} + env: + - name: NRIA_LICENSE_KEY + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} + + - name: "NRIA_OVERRIDE_HOSTNAME_SHORT" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + + - name: "NRIA_OVERRIDE_HOSTNAME" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + + {{- if not (include "newrelic.common.privileged" .) }} + # Override NRIA_OVERRIDE_HOST_ROOT to empty if unprivileged. This must be done as an env var as the + # `k8s-events-forwarder` and `infrastructure-bundle` images ship this very same env var set to /host. + - name: "NRIA_OVERRIDE_HOST_ROOT" + value: "" + {{- end }} + + - name: "NRI_KUBERNETES_NODE_NAME" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + + {{- if .Values.useNodeNameAsDisplayName }} + - name: "NRIA_DISPLAY_NAME" + {{- if .Values.prefixDisplayNameWithCluster }} + value: "{{ include "newrelic.common.cluster" . }}:$(NRI_KUBERNETES_NODE_NAME)" + {{- else }} + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + {{- end }} + {{- end }} + + {{- /* Needed to populate clustername in integration metrics */}} + - name: "CLUSTER_NAME" + value: {{ include "newrelic.common.cluster" . }} + - name: "NRIA_PASSTHROUGH_ENVIRONMENT" + value: "CLUSTER_NAME" + + {{- /* Needed for autodiscovery since hostNetwork=false */}} + - name: "NRIA_HOST" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "status.hostIP" + + {{- with .Values.kubelet.extraEnv }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.kubelet.extraEnvFrom }} + envFrom: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: config + mountPath: /etc/newrelic-infra.yml + subPath: newrelic-infra.yml + - name: nri-integrations-cfg-volume + mountPath: /etc/newrelic-infra/integrations.d/ + {{- if include "newrelic.common.privileged" . }} + - name: dev + mountPath: /dev + - name: host-containerd-socket + mountPath: /run/containerd/containerd.sock + - name: host-docker-socket + mountPath: /var/run/docker.sock + - name: log + mountPath: /var/log + - name: host-volume + mountPath: /host + mountPropagation: HostToContainer + readOnly: true + {{- end }} + - mountPath: /var/db/newrelic-infra/data + name: agent-tmpfs-data + - mountPath: /var/db/newrelic-infra/user_data + name: agent-tmpfs-user-data + - mountPath: /tmp + name: agent-tmpfs-tmp + {{- with .Values.kubelet.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.kubelet.resources }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + volumes: + {{- if include "newrelic.common.privileged" . }} + - name: dev + hostPath: + path: /dev + - name: host-containerd-socket + hostPath: + path: /run/containerd/containerd.sock + - name: host-docker-socket + hostPath: + path: /var/run/docker.sock + - name: log + hostPath: + path: /var/log + - name: host-volume + hostPath: + path: / + {{- end }} + - name: agent-tmpfs-data + emptyDir: {} + - name: agent-tmpfs-user-data + emptyDir: {} + - name: agent-tmpfs-tmp + emptyDir: {} + - name: nri-kubernetes-config + configMap: + name: {{ include "nriKubernetes.kubelet.fullname" . }} + items: + - key: nri-kubernetes.yml + path: nri-kubernetes.yml + - name: config + configMap: + name: {{ include "nriKubernetes.kubelet.fullname.agent" . }} + items: + - key: newrelic-infra.yml + path: newrelic-infra.yml + - name: nri-integrations-cfg-volume + configMap: + name: {{ include "nriKubernetes.kubelet.fullname.integrations" . }} + {{- with .Values.kubelet.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with include "nriKubernetes.kubelet.affinity" . }} + affinity: + {{- . | nindent 8 }} + {{- end }} + {{- with include "nriKubernetes.kubelet.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} + nodeSelector: + kubernetes.io/os: linux + {{- with .Values.kubelet.nodeSelector | default (fromYaml (include "newrelic.common.nodeSelector" .)) }} + {{- toYaml . | nindent 8 }} + {{- end -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/integrations-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/integrations-configmap.yaml new file mode 100644 index 000000000..abf381f38 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/integrations-configmap.yaml @@ -0,0 +1,72 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.kubelet.fullname.integrations" . }} +data: + # This ConfigMap holds config files for integrations. They should have the following format: + #redis-config.yml: | + # # Run auto discovery to find pods with label "app=redis" + # discovery: + # command: + # # Run discovery for Kubernetes. Use the following optional arguments: + # # --namespaces: Comma separated list of namespaces to discover pods on + # # --tls: Use secure (TLS) connection + # # --port: Port used to connect to the kubelet. Default is 10255 + # exec: /var/db/newrelic-infra/nri-discovery-kubernetes --port PORT --tls + # match: + # label.app: redis + # integrations: + # - name: nri-redis + # env: + # # using the discovered IP as the hostname address + # HOSTNAME: ${discovery.ip} + # PORT: 6379 + # KEYS: '{"0":[""],"1":[""]}' + # REMOTE_MONITORING: true + # labels: + # env: production + {{- if .Values.integrations -}} + {{- range $k, $v := .Values.integrations -}} + {{- $k | trimSuffix ".yaml" | trimSuffix ".yml" | nindent 2 -}}.yaml: |- + {{- $v | toYaml | nindent 4 -}} + {{- end }} + {{- end }} + + {{- /* This template will add and template the integrations in the old .Values.integrations_config */}} + {{- include "newrelic.compatibility.integrations" . | nindent 2 }} + + {{- /* This template will add Pixie Health check to the integrations */}} + {{- if .Values.selfMonitoring.pixie.enabled }} + pixie-health-check.yaml: | + --- + # This Flex config performs periodic checks of the Pixie + # /healthz and /statusz endpoints exposed by the Pixie Cloud Connector. + # A status for each endpoint is sent to New Relic in a pixieHealthCheck event. + # + # If Pixie is not installed in the cluster, no events will be generated. + # This can also be disabled with enablePixieHealthCheck: false in the values.yaml file. + discovery: + command: + exec: /var/db/newrelic-infra/nri-discovery-kubernetes --tls --port 10250 + match: + label.name: vizier-cloud-connector + integrations: + - name: nri-flex + interval: 60s + config: + name: pixie-health-check + apis: + - event_type: pixieHealth + commands: + - run: curl --insecure -s https://${discovery.ip}:50800/healthz | xargs | awk '{print "cloud_connector_health:"$1}' + split_by: ":" + merge: pixieHealthCheck + - event_type: pixieStatus + commands: + - run: curl --insecure -s https://${discovery.ip}:50800/statusz | awk '{if($1 == ""){ print "cloud_connector_status:OK" } else { print "cloud_connector_status:"$1 }}' + split_by: ":" + merge: pixieHealthCheck + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/scraper-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/scraper-configmap.yaml new file mode 100644 index 000000000..e43b5227f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/kubelet/scraper-configmap.yaml @@ -0,0 +1,18 @@ +{{- if .Values.kubelet.enabled -}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "nriKubernetes.kubelet.fullname" . }} + namespace: {{ .Release.Namespace }} +data: + nri-kubernetes.yml: | + {{- (merge .Values.common.config (include "newrelic.integrationConfigDefaults" . | fromYaml)) | toYaml | nindent 4 }} + kubelet: + enabled: true + {{- if .Values.kubelet.config }} + {{- toYaml .Values.kubelet.config | nindent 6 }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/podsecuritypolicy.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..5b5058511 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/podsecuritypolicy.yaml @@ -0,0 +1,26 @@ +{{- if .Values.rbac.pspEnabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: privileged-{{ include "newrelic.common.naming.fullname" . }} +spec: + allowedCapabilities: + - '*' + fsGroup: + rule: RunAsAny + privileged: true + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - '*' + hostPID: true + hostIPC: true + hostNetwork: true + hostPorts: + - min: 1 + max: 65536 +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/secret.yaml new file mode 100644 index 000000000..f558ee86c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/secret.yaml @@ -0,0 +1,2 @@ +{{- /* Common library will take care of creating the secret or not. */}} +{{- include "newrelic.common.license.secret" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/serviceaccount.yaml new file mode 100644 index 000000000..f987cc512 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/values.yaml new file mode 100644 index 000000000..5aaa12327 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-infrastructure/values.yaml @@ -0,0 +1,602 @@ +# -- Override the name of the chart +nameOverride: "" +# -- Override the full name of the release +fullnameOverride: "" + +# -- Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster` +cluster: "" +# -- This set this license key to use. Can be configured also with `global.licenseKey` +licenseKey: "" +# -- In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` +customSecretName: "" +# -- In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` +customSecretLicenseKey: "" + +# -- Images used by the chart for the integration and agents. +# @default -- See `values.yaml` +images: + # -- The secrets that are needed to pull images from a custom registry. + pullSecrets: [] + # - name: regsecret + # -- Image for the New Relic Infrastructure Agent sidecar. + # @default -- See `values.yaml` + forwarder: + registry: "" + repository: newrelic/k8s-events-forwarder + tag: 1.53.0 + pullPolicy: IfNotPresent + # -- Image for the New Relic Infrastructure Agent plus integrations. + # @default -- See `values.yaml` + agent: + registry: "" + repository: newrelic/infrastructure-bundle + tag: 3.2.47 + pullPolicy: IfNotPresent + # -- Image for the New Relic Kubernetes integration. + # @default -- See `values.yaml` + integration: + registry: "" + repository: newrelic/nri-kubernetes + tag: + pullPolicy: IfNotPresent + +# -- Config that applies to all instances of the solution: kubelet, ksm, control plane and sidecars. +# @default -- See `values.yaml` +common: + # Configuration entries that apply to all instances of the integration: kubelet, ksm and control plane. + config: + # common.config.interval -- (duration) Intervals larger than 40s are not supported and will cause the NR UI to not + # behave properly. Any non-nil value will override the `lowDataMode` default. + # @default -- `15s` (See [Low data mode](README.md#low-data-mode)) + interval: + # -- Config for filtering ksm and kubelet metrics by namespace. + namespaceSelector: {} + # If you want to include only namespaces with a given label you could do so by adding: + # matchLabels: + # newrelic.com/scrape: true + # Otherwise you can build more complex filters and include or exclude certain namespaces by adding one or multiple + # expressions that are added, for instance: + # matchExpressions: + # - {key: newrelic.com/scrape, operator: NotIn, values: ["false"]} + + # -- Config for the Infrastructure agent. + # Will be used by the forwarder sidecars and the agent running integrations. + # See: https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + agentConfig: {} + +# lowDataMode -- (bool) Send less data by incrementing the interval from `15s` (the default when `lowDataMode` is `false` or `nil`) to `30s`. +# Non-nil values of `common.config.interval` will override this value. +# @default -- `false` (See [Low data mode](README.md#low-data-mode)) +lowDataMode: + +# sink - Configuration for the scraper sink. +sink: + http: + # -- The amount of time the scraper container to probe infra agent sidecar container before giving up and restarting during pod starts. + probeTimeout: 90s + # -- The amount of time the scraper container to backoff when it fails to probe infra agent sidecar. + probeBackoff: 5s + +# kubelet -- Configuration for the DaemonSet that collects metrics from the Kubelet. +# @default -- See `values.yaml` +kubelet: + # -- Enable kubelet monitoring. + # Advanced users only. Setting this to `false` is not supported and will break the New Relic experience. + enabled: true + annotations: {} + # -- Tolerations for the control plane DaemonSet. + # @default -- Schedules in all tainted nodes + tolerations: + - operator: "Exists" + effect: "NoSchedule" + - operator: "Exists" + effect: "NoExecute" + nodeSelector: {} + # -- (bool) Sets pod's hostNetwork. When set bypasses global/common variable + # @default -- Not set + hostNetwork: + affinity: {} + # -- Config for the Infrastructure agent that will forward the metrics to the backend and will run the integrations in this cluster. + # It will be merged with the configuration in `.common.agentConfig`. You can see all the agent configurations in + # [New Relic docs](https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/) + # e.g. you can set `passthrough_environment` int the [config file](https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/configure-infrastructure-agent/#config-file) + # so the agent let use that environment variables to the integrations. + agentConfig: {} + # passthrough_environment: + # - A_ENVIRONMENT_VARIABLE_SET_IN_extraEnv + # - A_ENVIRONMENT_VARIABLE_SET_IN_A_CONFIG_MAP_SET_IN_entraEnvForm + + # -- Add user environment variables to the agent + extraEnv: [] + # -- Add user environment from configMaps or secrets as variables to the agent + extraEnvFrom: [] + # -- Volumes to mount in the containers + extraVolumes: [] + # -- Defines where to mount volumes specified with `extraVolumes` + extraVolumeMounts: [] + initContainers: [] + resources: + limits: + memory: 300M + requests: + cpu: 100m + memory: 150M + config: + # -- Timeout for the kubelet APIs contacted by the integration + timeout: 10s + # -- Number of retries after timeout expired + retries: 3 + # -- Max number of scraper rerun when scraper runtime error happens + scraperMaxReruns: 4 + # port: + # scheme: + +# ksm -- Configuration for the Deployment that collects state metrics from KSM (kube-state-metrics). +# @default -- See `values.yaml` +ksm: + # -- Enable cluster state monitoring. + # Advanced users only. Setting this to `false` is not supported and will break the New Relic experience. + enabled: true + annotations: {} + # -- Tolerations for the KSM Deployment. + # @default -- Schedules in all tainted nodes + tolerations: + - operator: "Exists" + effect: "NoSchedule" + - operator: "Exists" + effect: "NoExecute" + nodeSelector: {} + # -- (bool) Sets pod's hostNetwork. When set bypasses global/common variable + # @default -- Not set + hostNetwork: + # -- Affinity for the KSM Deployment. + # @default -- Deployed in the same node as KSM + affinity: + podAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + app.kubernetes.io/name: kube-state-metrics + weight: 100 + # -- Config for the Infrastructure agent that will forward the metrics to the backend. It will be merged with the configuration in `.common.agentConfig` + # See: https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + agentConfig: {} + extraEnv: [] + extraEnvFrom: [] + extraVolumes: [] + extraVolumeMounts: [] + initContainers: [] + # -- Resources for the KSM scraper pod. + # Keep in mind that sharding is not supported at the moment, so memory usage for this component ramps up quickly on + # large clusters. + # @default -- 100m/150M -/850M + resources: + limits: + memory: 850M # Bump me up if KSM pod shows restarts. + requests: + cpu: 100m + memory: 150M + config: + # -- Timeout for the ksm API contacted by the integration + timeout: 10s + # -- Number of retries after timeout expired + retries: 3 + # -- if specified autodiscovery is not performed and the specified URL is used + # staticUrl: "http://test.io:8080/metrics" + # -- Label selector that will be used to automatically discover an instance of kube-state-metrics running in the cluster. + selector: "app.kubernetes.io/name=kube-state-metrics" + # -- Scheme to use to connect to kube-state-metrics. Supported values are `http` and `https`. + scheme: "http" + # -- Restrict autodiscovery of the kube-state-metrics endpoint to those using a specific port. If empty or `0`, all endpoints are considered regardless of their port (recommended). + # port: 8080 + # -- Restrict autodiscovery of the kube-state-metrics service to a particular namespace. + # @default -- All namespaces are searched (recommended). + # namespace: "ksm-namespace" + +# controlPlane -- Configuration for the control plane scraper. +# @default -- See `values.yaml` +controlPlane: + # -- Deploy control plane monitoring component. + enabled: true + annotations: {} + # -- Tolerations for the control plane DaemonSet. + # @default -- Schedules in all tainted nodes + tolerations: + - operator: "Exists" + effect: "NoSchedule" + - operator: "Exists" + effect: "NoExecute" + nodeSelector: {} + # -- Affinity for the control plane DaemonSet. + # @default -- Deployed only in master nodes. + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node-role.kubernetes.io/control-plane + operator: Exists + - matchExpressions: + - key: node-role.kubernetes.io/controlplane + operator: Exists + - matchExpressions: + - key: node-role.kubernetes.io/etcd + operator: Exists + - matchExpressions: + - key: node-role.kubernetes.io/master + operator: Exists + # -- How to deploy the control plane scraper. If autodiscovery is in use, it should be `DaemonSet`. + # Advanced users using static endpoints set this to `Deployment` to avoid reporting metrics twice. + kind: DaemonSet + # -- Run Control Plane scraper with `hostNetwork`. + # `hostNetwork` is required for most control plane configurations, as they only accept connections from localhost. + hostNetwork: true + # -- Config for the Infrastructure agent that will forward the metrics to the backend. It will be merged with the configuration in `.common.agentConfig` + # See: https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + agentConfig: {} + extraEnv: [] + extraEnvFrom: [] + extraVolumes: [] + extraVolumeMounts: [] + initContainers: [] + resources: + limits: + memory: 300M + requests: + cpu: 100m + memory: 150M + config: + # -- Timeout for the Kubernetes APIs contacted by the integration + timeout: 10s + # -- Number of retries after timeout expired + retries: 3 + # -- etcd monitoring configuration + # @default -- Common settings for most K8s distributions. + etcd: + # -- Enable etcd monitoring. Might require manual configuration in some environments. + enabled: true + # Discover etcd pods using the following namespaces and selectors. + # If a pod matches the selectors, the scraper will attempt to reach it through the `endpoints` defined below. + autodiscover: + - selector: "tier=control-plane,component=etcd" + namespace: kube-system + # Set to true to consider only pods sharing the node with the scraper pod. + # This should be set to `true` if Kind is Daemonset, `false` otherwise. + matchNode: true + # Try to reach etcd using the following endpoints. + endpoints: + - url: https://localhost:4001 + insecureSkipVerify: true + auth: + type: bearer + - url: http://localhost:2381 + - selector: "k8s-app=etcd-manager-main" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:4001 + insecureSkipVerify: true + auth: + type: bearer + - selector: "k8s-app=etcd" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:4001 + insecureSkipVerify: true + auth: + type: bearer + # Openshift users might want to remove previous autodiscover entries and add this one instead. + # Manual steps are required to create a secret containing the required TLS certificates to connect to etcd. + # - selector: "app=etcd,etcd=true,k8s-app=etcd" + # namespace: openshift-etcd + # matchNode: true + # endpoints: + # - url: https://localhost:9979 + # insecureSkipVerify: true + # auth: + # type: mTLS + # mtls: + # secretName: secret-name + # secretNamespace: secret-namespace + + # -- staticEndpoint configuration. + # It is possible to specify static endpoint to scrape. If specified 'autodiscover' section is ignored. + # If set the static endpoint should be reachable, otherwise an error will be returned and the integration stops. + # Notice that if deployed as a daemonSet and not as a Deployment setting static URLs could lead to duplicate data + # staticEndpoint: + # url: https://url:port + # insecureSkipVerify: true + # auth: {} + + # -- Scheduler monitoring configuration + # @default -- Common settings for most K8s distributions. + scheduler: + # -- Enable scheduler monitoring. + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-scheduler" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10259 + insecureSkipVerify: true + auth: + type: bearer + - selector: "k8s-app=kube-scheduler" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10259 + insecureSkipVerify: true + auth: + type: bearer + - selector: "app=openshift-kube-scheduler,scheduler=true" + namespace: openshift-kube-scheduler + matchNode: true + endpoints: + - url: https://localhost:10259 + insecureSkipVerify: true + auth: + type: bearer + - selector: "app=openshift-kube-scheduler,scheduler=true" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10259 + insecureSkipVerify: true + auth: + type: bearer + # -- staticEndpoint configuration. + # It is possible to specify static endpoint to scrape. If specified 'autodiscover' section is ignored. + # If set the static endpoint should be reachable, otherwise an error will be returned and the integration stops. + # Notice that if deployed as a daemonSet and not as a Deployment setting static URLs could lead to duplicate data + # staticEndpoint: + # url: https://url:port + # insecureSkipVerify: true + # auth: {} + + # -- Controller manager monitoring configuration + # @default -- Common settings for most K8s distributions. + controllerManager: + # -- Enable controller manager monitoring. + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-controller-manager" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10257 + insecureSkipVerify: true + auth: + type: bearer + - selector: "k8s-app=kube-controller-manager" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10257 + insecureSkipVerify: true + auth: + type: bearer + - selector: "app=kube-controller-manager,kube-controller-manager=true" + namespace: openshift-kube-controller-manager + matchNode: true + endpoints: + - url: https://localhost:10257 + insecureSkipVerify: true + auth: + type: bearer + - selector: "app=kube-controller-manager,kube-controller-manager=true" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10257 + insecureSkipVerify: true + auth: + type: bearer + - selector: "app=controller-manager,controller-manager=true" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10257 + insecureSkipVerify: true + auth: + type: bearer + # mtls: + # secretName: secret-name + # secretNamespace: secret-namespace + # -- staticEndpoint configuration. + # It is possible to specify static endpoint to scrape. If specified 'autodiscover' section is ignored. + # If set the static endpoint should be reachable, otherwise an error will be returned and the integration stops. + # Notice that if deployed as a daemonSet and not as a Deployment setting static URLs could lead to duplicate data + # staticEndpoint: + # url: https://url:port + # insecureSkipVerify: true + # auth: {} + + # -- API Server monitoring configuration + # @default -- Common settings for most K8s distributions. + apiServer: + # -- Enable API Server monitoring + enabled: true + autodiscover: + - selector: "tier=control-plane,component=kube-apiserver" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:8443 + insecureSkipVerify: true + auth: + type: bearer + # Endpoint distributions target: Kind(v1.22.1) + - url: https://localhost:6443 + insecureSkipVerify: true + auth: + type: bearer + - url: http://localhost:8080 + - selector: "k8s-app=kube-apiserver" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:8443 + insecureSkipVerify: true + auth: + type: bearer + - url: http://localhost:8080 + - selector: "app=openshift-kube-apiserver,apiserver=true" + namespace: openshift-kube-apiserver + matchNode: true + endpoints: + - url: https://localhost:8443 + insecureSkipVerify: true + auth: + type: bearer + - url: https://localhost:6443 + insecureSkipVerify: true + auth: + type: bearer + - selector: "app=openshift-kube-apiserver,apiserver=true" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:8443 + insecureSkipVerify: true + auth: + type: bearer + # -- staticEndpoint configuration. + # It is possible to specify static endpoint to scrape. If specified 'autodiscover' section is ignored. + # If set the static endpoint should be reachable, otherwise an error will be returned and the integration stops. + # Notice that if deployed as a daemonSet and not as a Deployment setting static URLs could lead to duplicate data + # staticEndpoint: + # url: https://url:port + # insecureSkipVerify: true + # auth: {} + +# -- Update strategy for the deployed DaemonSets. +# @default -- See `values.yaml` +updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + +# -- Update strategy for the deployed Deployments. +# @default -- `type: Recreate` +strategy: + type: Recreate + +# -- Adds extra attributes to the cluster and all the metrics emitted to the backend. Can be configured also with `global.customAttributes` +customAttributes: {} + +# -- Settings controlling ServiceAccount creation. +# @default -- See `values.yaml` +serviceAccount: + # -- (bool) Whether the chart should automatically create the ServiceAccount objects required to run. + # @default -- `true` + create: + annotations: {} + # If not set and create is true, a name is generated using the fullname template + name: "" + +# -- Additional labels for chart objects. Can be configured also with `global.labels` +labels: {} +# -- Annotations to be added to all pods created by the integration. +podAnnotations: {} +# -- Additional labels for chart pods. Can be configured also with `global.podLabels` +podLabels: {} + +# -- Run the integration with full access to the host filesystem and network. +# Running in this mode allows reporting fine-grained cpu, memory, process and network metrics for your nodes. +privileged: true +# -- Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` +priorityClassName: "" +# -- (bool) Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` +# @default -- `false` +hostNetwork: +# -- Sets security context (at pod level). Can be configured also with `global.podSecurityContext` +podSecurityContext: {} +# -- Sets security context (at container level). Can be configured also with `global.containerSecurityContext` +containerSecurityContext: {} + +# -- Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` +dnsConfig: {} + +# Settings controlling RBAC objects creation. +rbac: + # rbac.create -- Whether the chart should automatically create the RBAC objects required to run. + create: true + # rbac.pspEnabled -- Whether the chart should create Pod Security Policy objects. + pspEnabled: false + +# -- Sets pod/node affinities set almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) +affinity: {} +# -- Sets pod's node selector almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) +nodeSelector: {} +# -- Sets pod's tolerations to node taints almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) +tolerations: [] + +# -- Config files for other New Relic integrations that should run in this cluster. +integrations: {} +# If you wish to monitor services running on Kubernetes you can provide integrations +# configuration under `integrations`. You just need to create a new entry where +# the key is the filename of the configuration file and the value is the content of +# the integration configuration. +# The data is the actual integration configuration as described in the spec here: +# https://docs.newrelic.com/docs/integrations/integrations-sdk/file-specifications/integration-configuration-file-specifications-agent-v180 +# For example, if you wanted to monitor a Redis instance that has a label "app=sampleapp" +# you could do so by adding following entry: +# nri-redis-sampleapp: +# discovery: +# command: +# # Run NRI Discovery for Kubernetes +# # https://github.com/newrelic/nri-discovery-kubernetes +# exec: /var/db/newrelic-infra/nri-discovery-kubernetes +# match: +# label.app: sampleapp +# integrations: +# - name: nri-redis +# env: +# # using the discovered IP as the hostname address +# HOSTNAME: ${discovery.ip} +# PORT: 6379 +# labels: +# env: test + +# -- (bool) Collect detailed metrics from processes running in the host. +# This defaults to true for accounts created before July 20, 2020. +# ref: https://docs.newrelic.com/docs/release-notes/infrastructure-release-notes/infrastructure-agent-release-notes/new-relic-infrastructure-agent-1120 +# @default -- `false` +enableProcessMetrics: + +# Prefix nodes display name with cluster to reduce chances of collisions +# prefixDisplayNameWithCluster: false + +# 'true' will use the node name as the name for the "host", +# note that it may cause data collision if the node name is the same in different clusters +# and prefixDisplayNameWithCluster is not set to true. +# 'false' will use the host name as the name for the "host". +# useNodeNameAsDisplayName: true + +selfMonitoring: + pixie: + # selfMonitoring.pixie.enabled -- Enables the Pixie Health Check nri-flex config. + # This Flex config performs periodic checks of the Pixie /healthz and /statusz endpoints exposed by the Pixie + # Cloud Connector. A status for each endpoint is sent to New Relic in a pixieHealthCheck event. + enabled: false + + +# -- Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port`. Can be configured also with `global.proxy` +proxy: "" + +# -- (bool) Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` +# @default -- `false` +nrStaging: +fedramp: + # -- (bool) Enables FedRAMP. Can be configured also with `global.fedramp.enabled` + # @default -- `false` + enabled: + +# -- (bool) Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` +# @default -- `false` +verboseLog: diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/.helmignore new file mode 100644 index 000000000..1ed4e226e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/.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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ + +templates/apiservice/job-patch/README.md diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/Chart.lock new file mode 100644 index 000000000..fc2918195 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +digest: sha256:fa87cb007564a39a72739a3e850a91d6b03c0fc27a1115deac042b3ef77b4142 +generated: "2024-06-22T03:37:58.957965768Z" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/Chart.yaml new file mode 100644 index 000000000..2153a342f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +appVersion: 0.13.0 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +description: A Helm chart to deploy the New Relic Kubernetes Metrics Adapter. +home: https://hub.docker.com/r/newrelic/newrelic-k8s-metrics-adapter +icon: https://newrelic.com/assets/newrelic/source/NewRelic-logo-square.svg +keywords: +- infrastructure +- newrelic +- monitoring +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +name: newrelic-k8s-metrics-adapter +sources: +- https://github.com/newrelic/newrelic-k8s-metrics-adapter +- https://github.com/newrelic/newrelic-k8s-metrics-adapter/tree/main/charts/newrelic-k8s-metrics-adapter +version: 1.11.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/README.md new file mode 100644 index 000000000..9f3943ec4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/README.md @@ -0,0 +1,139 @@ +[![New Relic Experimental header](https://github.com/newrelic/opensource-website/raw/master/src/images/categories/Experimental.png)](https://opensource.newrelic.com/oss-category/#new-relic-experimental) + +# newrelic-k8s-metrics-adapter + +A Helm chart to deploy the New Relic Kubernetes Metrics Adapter. + +**Homepage:** + +## Source Code + +* +* + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://helm-charts.newrelic.com | common-library | 1.2.0 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Node affinity to use for scheduling. | +| apiServicePatchJob.image | object | See `values.yaml`. | Registry, repository, tag, and pull policy for the job container image. | +| apiServicePatchJob.volumeMounts | list | `[]` | Additional Volume mounts for Cert Job, you might want to mount tmp if Pod Security Policies. | +| apiServicePatchJob.volumes | list | `[]` | Additional Volumes for Cert Job. | +| certManager.enabled | bool | `false` | Use cert manager for APIService certs, rather than the built-in patch job. | +| config.accountID | string | `nil` | New Relic [Account ID](https://docs.newrelic.com/docs/accounts/accounts-billing/account-structure/account-id/) where the configured metrics are sourced from. (**Required**) | +| config.cacheTTLSeconds | int | `30` | Period of time in seconds in which a cached value of a metric is consider valid. | +| config.externalMetrics | string | See `values.yaml` | Contains all the external metrics definition of the adapter. Each key of the externalMetric entry represents the metric name and contains the parameters that defines it. | +| config.nrdbClientTimeoutSeconds | int | 30 | Defines the NRDB client timeout. The maximum allowed value is 120. | +| config.region | string | Automatically detected from `licenseKey`. | New Relic account region. If not set, it will be automatically derived from the License Key. | +| containerSecurityContext | string | `nil` | Configure containerSecurityContext | +| extraEnv | list | `[]` | Array to add extra environment variables | +| extraEnvFrom | list | `[]` | Array to add extra envFrom | +| extraVolumeMounts | list | `[]` | Add extra volume mounts | +| extraVolumes | list | `[]` | Array to add extra volumes | +| fullnameOverride | string | `""` | To fully override common.naming.fullname | +| image | object | See `values.yaml`. | Registry, repository, tag, and pull policy for the container image. | +| image.pullSecrets | list | `[]` | The image pull secrets. | +| nodeSelector | object | `{}` | Node label to use for scheduling. | +| personalAPIKey | string | `nil` | New Relic [Personal API Key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#user-api-key) (stored in a secret). Used to connect to NerdGraph in order to fetch the configured metrics. (**Required**) | +| podAnnotations | string | `nil` | Additional annotations to apply to the pod(s). | +| podSecurityContext | string | `nil` | Configure podSecurityContext | +| proxy | string | `nil` | Configure proxy for the metrics-adapter. | +| rbac.pspEnabled | bool | `false` | Whether the chart should create Pod Security Policy objects. | +| replicas | int | `1` | Number of replicas in the deployment. | +| resources | object | See `values.yaml` | Resources you wish to assign to the pod. | +| serviceAccount.create | string | `true` | Specifies whether a ServiceAccount should be created for the job and the deployment. false avoids creation, true or empty will create the ServiceAccount | +| serviceAccount.name | string | Automatically generated. | If `serviceAccount.create` this will be the name of the ServiceAccount to use. If not set and create is true, a name is generated using the fullname template. If create is false, a serviceAccount with the given name must exist | +| tolerations | list | `[]` | List of node taints to tolerate (requires Kubernetes >= 1.6) | +| verboseLog | bool | `false` | Enable metrics adapter verbose logs. | + +## Example + +Make sure you have [added the New Relic chart repository.](../../README.md#install) + +Because of metrics configuration, we recommend to use an external values file to deploy the chart. An example with the required parameters looks like: + +```yaml +cluster: ClusterName +personalAPIKey: +config: + accountID: + externalMetrics: + nginx_average_requests: + query: "FROM Metric SELECT average(nginx.server.net.requestsPerSecond) SINCE 2 MINUTES AGO" +``` + +Then, to install this chart, run the following command: + +```sh +helm upgrade --install [release-name] newrelic-k8s-metrics-adapter/newrelic-k8s-metrics-adapter --values [values file path] +``` + +Once deployed the metric `nginx_average_requests` will be available to use by any HPA. This is and example of an HPA yaml using this metric: + +```yaml +kind: HorizontalPodAutoscaler +apiVersion: autoscaling/v2beta2 +metadata: + name: nginx-scaler +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: nginx + minReplicas: 1 + maxReplicas: 10 + metrics: + - type: External + external: + metric: + name: nginx_average_requests + selector: + matchLabels: + k8s.namespaceName: nginx + target: + type: Value + value: 10000 +``` + +The NRQL query that will be run to get the `nginx_average_requests` value will be: + +```sql +FROM Metric SELECT average(nginx.server.net.requestsPerSecond) WHERE clusterName='ClusterName' AND `k8s.namespaceName`='nginx' SINCE 2 MINUTES AGO +``` + +## External Metrics + +An example of multiple external metrics defined: + +```yaml +externalMetrics: + nginx_average_requests: + query: "FROM Metric SELECT average(nginx.server.net.requestsPerSecond) SINCE 2 MINUTES AGO" + container_average_cores_utilization: + query: "FROM Metric SELECT average(`k8s.container.cpuCoresUtilization`) SINCE 2 MINUTES AGO" +``` + +## Resources + +The default set of resources assigned to the newrelic-k8s-metrics-adapter pods is shown below: + +```yaml +resources: + limits: + memory: 80M + requests: + cpu: 100m + memory: 30M +``` + +## Maintainers + +* [juanjjaramillo](https://github.com/juanjjaramillo) +* [csongnr](https://github.com/csongnr) +* [dbudziwojskiNR](https://github.com/dbudziwojskiNR) diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/README.md.gotmpl new file mode 100644 index 000000000..1de8c9553 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/README.md.gotmpl @@ -0,0 +1,107 @@ +[![New Relic Experimental header](https://github.com/newrelic/opensource-website/raw/master/src/images/categories/Experimental.png)](https://opensource.newrelic.com/oss-category/#new-relic-experimental) + +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + +## Example + +Make sure you have [added the New Relic chart repository.](../../README.md#install) + +Because of metrics configuration, we recommend to use an external values file to deploy the chart. An example with the required parameters looks like: + +```yaml +cluster: ClusterName +personalAPIKey: +config: + accountID: + externalMetrics: + nginx_average_requests: + query: "FROM Metric SELECT average(nginx.server.net.requestsPerSecond) SINCE 2 MINUTES AGO" +``` + +Then, to install this chart, run the following command: + +```sh +helm upgrade --install [release-name] newrelic-k8s-metrics-adapter/newrelic-k8s-metrics-adapter --values [values file path] +``` + +Once deployed the metric `nginx_average_requests` will be available to use by any HPA. This is and example of an HPA yaml using this metric: + +```yaml +kind: HorizontalPodAutoscaler +apiVersion: autoscaling/v2beta2 +metadata: + name: nginx-scaler +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: nginx + minReplicas: 1 + maxReplicas: 10 + metrics: + - type: External + external: + metric: + name: nginx_average_requests + selector: + matchLabels: + k8s.namespaceName: nginx + target: + type: Value + value: 10000 +``` + +The NRQL query that will be run to get the `nginx_average_requests` value will be: + +```sql +FROM Metric SELECT average(nginx.server.net.requestsPerSecond) WHERE clusterName='ClusterName' AND `k8s.namespaceName`='nginx' SINCE 2 MINUTES AGO +``` + +## External Metrics + +An example of multiple external metrics defined: + +```yaml +externalMetrics: + nginx_average_requests: + query: "FROM Metric SELECT average(nginx.server.net.requestsPerSecond) SINCE 2 MINUTES AGO" + container_average_cores_utilization: + query: "FROM Metric SELECT average(`k8s.container.cpuCoresUtilization`) SINCE 2 MINUTES AGO" +``` + +## Resources + +The default set of resources assigned to the newrelic-k8s-metrics-adapter pods is shown below: + +```yaml +resources: + limits: + memory: 80M + requests: + cpu: 100m + memory: 30M +``` + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/Chart.yaml new file mode 100644 index 000000000..b65ac15d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +- name: kang-makes + url: https://github.com/kang-makes +name: common-library +type: library +version: 1.2.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/DEVELOPERS.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/DEVELOPERS.md new file mode 100644 index 000000000..3ccc108e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/DEVELOPERS.md @@ -0,0 +1,663 @@ +# Functions/templates documented for chart writers +Here is some rough documentation separated by the file that contains the function, the function +name and how to use it. We are not covering functions that start with `_` (e.g. +`newrelic.common.license._licenseKey`) because they are used internally by this library for +other helpers. Helm does not have the concept of "public" or "private" functions/templates so +this is a convention of ours. + +## _naming.tpl +These functions are used to name objects. + +### `newrelic.common.naming.name` +This is the same as the idiomatic `CHART-NAME.name` that is created when you use `helm create`. + +It honors `.Values.nameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.name" . }} +``` + +### `newrelic.common.naming.fullname` +This is the same as the idiomatic `CHART-NAME.fullname` that is created when you use `helm create` + +It honors `.Values.fullnameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.fullname" . }} +``` + +### `newrelic.common.naming.chart` +This is the same as the idiomatic `CHART-NAME.chart` that is created when you use `helm create`. + +It is mostly useless for chart writers. It is used internally for templating the labels but there +is no reason to keep it "private". + +Usage: +```mustache +{{ include "newrelic.common.naming.chart" . }} +``` + +### `newrelic.common.naming.truncateToDNS` +This is a useful template that could be used to trim a string to 63 chars and does not end with a dash (`-`). +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $truncatedName := include "newrelic.common.naming.truncateToDNS" $nameToTruncate }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-string-that-should-be */ -}} +``` + +### `newrelic.common.naming.truncateToDNSWithSuffix` +This template function is the same as the above but instead of receiving a string you should give a `dict` +with a `name` and a `suffix`. This function will join them with a dash (`-`) and trim the `name` so the +result of `name-suffix` is no more than 63 chars + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $suffix := "A-NOT-SO-LONG-SUFFIX" }} +{{- $truncatedName := include "truncateToDNSWithSuffix" (dict "name" $nameToTruncate "suffix" $suffix) }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-A-NOT-SO-LONG-SUFFIX */ -}} +``` + + + +## _labels.tpl +### `newrelic.common.labels`, `newrelic.common.labels.selectorLabels` and `newrelic.common.labels.podLabels` +These are functions that are used to label objects. They are configured by this `values.yaml` +```yaml +global: + podLabels: {} # included in all the pods of all the charts that implement this library + labels: {} # included in all the objects of all the charts that implement this library +podLabels: {} # included in all the pods of this chart +labels: {} # included in all the objects of this chart +``` + +label maps are merged from global to local values. + +And chart writer should use them like this: +```mustache +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} +``` + +`newrelic.common.labels.podLabels` includes `newrelic.common.labels.selectorLabels` automatically. + + + +## _priority-class-name.tpl +### `newrelic.common.priorityClassName` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + priorityClassName: "" +priorityClassName: "" +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `priorityClassName` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} +``` + + + +## _hostnetwork.tpl +### `newrelic.common.hostNetwork` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + hostNetwork: # Note that this is empty (nil) +hostNetwork: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `hostNetwork` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.hostNetwork" . }} + hostNetwork: {{ . }} + {{- end }} +``` + +### `newrelic.common.hostNetwork.value` +This function is an abstraction of the function above but this returns directly "true" or "false". + +Be careful with using this with an `if` as Helm does evaluate "false" (string) as `true`. + +Usage (example in a pod spec): +```mustache +spec: + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} +``` + + + +## _dnsconfig.tpl +### `newrelic.common.dnsConfig` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + dnsConfig: {} +dnsConfig: {} +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `dnsConfig` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _images.tpl +These functions help us to deal with how images are templated. This allows setting `registries` +where to fetch images globally while being flexible enough to fit in different maps of images +and deployments with one or more images. This is the example of a complex `values.yaml` that +we are going to use during the documentation of these functions: + +```yaml +global: + images: + registry: nexus-3-instance.internal.clients-domain.tld +jobImage: + registry: # defaults to "example.tld" when empty in these examples + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent + pullSecrets: [] +images: + integration: + registry: + repository: newrelic/nri-kube-events + tag: 1.8.0 + pullPolicy: IfNotPresent + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.22.0 + pullPolicy: IfNotPresent + pullSecrets: [] +``` + +### `newrelic.common.images.image` +This will return a string with the image ready to be downloaded that includes the registry, the image and the tag. +`defaultRegistry` is used to keep `registry` field empty in `values.yaml` so you can override the image using +`global.images.registry`, your local `jobImage.registry` and be able to fallback to a registry that is not `docker.io` +(Or the default repository that the client could have set in the CRI). + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.image" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.registry` +It returns the registry from the global or local values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.registry" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.repository` +It returns the image from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.tag` +It returns the image's tag from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.renderPullSecrets` +If returns a merged map that contains the pull secrets from the global configuration and the local one. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.jobImage.pullSecrets "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +``` + + + +## _serviceaccount.tpl +These functions are used to evaluate if the service account should be created, with which name and add annotations to it. + +The functions that the common library has implemented for service accounts are: +* `newrelic.common.serviceAccount.create` +* `newrelic.common.serviceAccount.name` +* `newrelic.common.serviceAccount.annotations` + +Usage: +```mustache +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +``` + + + +## _affinity.tpl, _nodeselector.tpl and _tolerations.tpl +These three files are almost the same and they follow the idiomatic way of `helm create`. + +Each function also looks if there is a global value like the other helpers. +```yaml +global: + affinity: {} + nodeSelector: {} + tolerations: [] +affinity: {} +nodeSelector: {} +tolerations: [] +``` + +The values here are replaced instead of be merged. If a value at root level is found, the global one is ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _agent-config.tpl +### `newrelic.common.agentConfig.defaults` +This returns a YAML that the agent can use directly as a config that includes other options from the values file like verbose mode, +custom attributes, FedRAMP and such. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include newrelic.common.naming.truncateToDNSWithSuffix (dict "name" (include "newrelic.common.naming.fullname" .) suffix "agent-config") }} + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "newrelic.common.agentConfig.defaults" . | nindent 4 }} +``` + + + +## _cluster.tpl +### `newrelic.common.cluster` +Returns the cluster name + +Usage: +```mustache +{{ include "newrelic.common.cluster" . }} +``` + + + +## _custom-attributes.tpl +### `newrelic.common.customAttributes` +Return custom attributes in YAML format. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + name: example +data: + custom-attributes.yaml: | + {{- include "newrelic.common.customAttributes" . | nindent 4 }} + custom-attributes.json: | + {{- include "newrelic.common.customAttributes" . | fromYaml | toJson | nindent 4 }} +``` + + + +## _fedramp.tpl +### `newrelic.common.fedramp.enabled` +Returns true if FedRAMP is enabled or an empty string if not. It can be safely used in conditionals as an empty string is a Helm falsiness. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled" . }} +``` + +### `newrelic.common.fedramp.enabled.value` +Returns true if FedRAMP is enabled or false if not. This is to have the value of FedRAMP ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled.value" . }} +``` + + + +## _license.tpl +### `newrelic.common.license.secretName` and ### `newrelic.common.license.secretKeyName` +Returns the secret and key inside the secret where to read the license key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the license key. + +To create the secret use `newrelic.common.license.secret`. + +Usage: +```mustache +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + containers: + - name: agent + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} +``` + + + +## _license_secret.tpl +### `newrelic.common.license.secret` +This function templates the secret that is used by agents and integrations with the license Key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any license key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.license.secret" . -}} +``` + + + +## _insights.tpl +### `newrelic.common.insightsKey.secretName` and ### `newrelic.common.insightsKey.secretKeyName` +Returns the secret and key inside the secret where to read the insights key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the insights key. + +To create the secret use `newrelic.common.insightsKey.secret`. + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: statsd +spec: + containers: + - name: statsd + env: + - name: "INSIGHTS_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + key: {{ include "newrelic.common.insightsKey.secretKeyName" . }} +``` + + + +## _insights_secret.tpl +### `newrelic.common.insightsKey.secret` +This function templates the secret that is used by agents and integrations with the insights key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any insights key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.insightsKey.secret" . -}} +``` + + + +## _low-data-mode.tpl +### `newrelic.common.lowDataMode` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + lowDataMode: # Note that this is empty (nil) +lowDataMode: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `lowdataMode` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.lowDataMode" . }} +``` + + + +## _privileged.tpl +### `newrelic.common.privileged` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + privileged: # Note that this is empty (nil) +privileged: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `privileged` is defined, the global one is going to be always ignored. + +Chart writers could override this and put directly a `true` in the `values.yaml` to override the +default of the common library. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.privileged" . }} +``` + +### `newrelic.common.privileged.value` +Returns true if privileged mode is enabled or false if not. This is to have the value of privileged ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.privileged.value" . }} +``` + + + +## _proxy.tpl +### `newrelic.common.proxy` +Returns the proxy URL configured by the user. + +Usage: +```mustache +{{ include "newrelic.common.proxy" . }} +``` + + + +## _security-context.tpl +Use these functions to share the security context among all charts. Useful in clusters that have security enforcing not to +use the root user (like OpenShift) or users that have an admission webhooks. + +The functions are: +* `newrelic.common.securityContext.container` +* `newrelic.common.securityContext.pod` + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + spec: + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + containers: + - name: example + {{- with include "nriKubernetes.securityContext.container" . }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} +``` + + + +## _staging.tpl +### `newrelic.common.nrStaging` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + nrStaging: # Note that this is empty (nil) +nrStaging: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `nrStaging` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging" . }} +``` + +### `newrelic.common.nrStaging.value` +Returns true if staging is enabled or false if not. This is to have the staging value ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging.value" . }} +``` + + + +## _verbose-log.tpl +### `newrelic.common.verboseLog` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + verboseLog: # Note that this is empty (nil) +verboseLog: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `verboseLog` is defined, the global one is going to be always ignored. + +Usage: +```mustache +{{ include "newrelic.common.verboseLog" . }} +``` + +### `newrelic.common.verboseLog.valueAsBoolean` +Returns true if verbose is enabled or false if not. This is to have the verbose value ready to be templated as a boolean + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsBoolean" . }} +``` + +### `newrelic.common.verboseLog.valueAsInt` +Returns 1 if verbose is enabled or 0 if not. This is to have the verbose value ready to be templated as an integer + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsInt" . }} +``` diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/README.md new file mode 100644 index 000000000..10f08ca67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/README.md @@ -0,0 +1,106 @@ +# Helm Common library + +The common library is a way to unify the UX through all the Helm charts that implement it. + +The tooling suite that New Relic is huge and growing and this allows to set things globally +and locally for a single chart. + +## Documentation for chart writers + +If you are writing a chart that is going to use this library you can check the [developers guide](/library/common-library/DEVELOPERS.md) to see all +the functions/templates that we have implemented, what they do and how to use them. + +## Values managed globally + +We want to have a seamless experience through all the charts so we created this library that tries to standardize the behaviour +of all the charts. Sadly, because of the complexity of all these integrations, not all the charts behave exactly as expected. + +An example is `newrelic-infrastructure` that ignores `hostNetwork` in the control plane scraper because most of the users has the +control plane listening in the node to `localhost`. + +For each chart that has a special behavior (or further information of the behavior) there is a "chart particularities" section +in its README.md that explains which is the expected behavior. + +At the time of writing this, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this +library and honors global options as described in this document. + +Here is a list of global options: + +| Global keys | Local keys | Default | Merged[1](#values-managed-globally-1) | Description | +|-------------|------------|---------|--------------------------------------------------|-------------| +| global.cluster | cluster | `""` | | Name of the Kubernetes cluster monitored | +| global.licenseKey | licenseKey | `""` | | This set this license key to use | +| global.customSecretName | customSecretName | `""` | | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there | +| global.customSecretLicenseKey | customSecretLicenseKey | `""` | | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located | +| global.podLabels | podLabels | `{}` | yes | Additional labels for chart pods | +| global.labels | labels | `{}` | yes | Additional labels for chart objects | +| global.priorityClassName | priorityClassName | `""` | | Sets pod's priorityClassName | +| global.hostNetwork | hostNetwork | `false` | | Sets pod's hostNetwork | +| global.dnsConfig | dnsConfig | `{}` | | Sets pod's dnsConfig | +| global.images.registry | See [Further information](#values-managed-globally-2) | `""` | | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.images.pullSecrets | See [Further information](#values-managed-globally-2) | `[]` | yes | Set secrets to be able to fetch images | +| global.podSecurityContext | podSecurityContext | `{}` | | Sets security context (at pod level) | +| global.containerSecurityContext | containerSecurityContext | `{}` | | Sets security context (at container level) | +| global.affinity | affinity | `{}` | | Sets pod/node affinities | +| global.nodeSelector | nodeSelector | `{}` | | Sets pod's node selector | +| global.tolerations | tolerations | `[]` | | Sets pod's tolerations to node taints | +| global.serviceAccount.create | serviceAccount.create | `true` | | Configures if the service account should be created or not | +| global.serviceAccount.name | serviceAccount.name | name of the release | | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. | +| global.serviceAccount.annotations | serviceAccount.annotations | `{}` | yes | Add these annotations to the service account we create | +| global.customAttributes | customAttributes | `{}` | | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.fedramp | fedramp | `false` | | Enables FedRAMP | +| global.lowDataMode | lowDataMode | `false` | | Reduces number of metrics sent in order to reduce costs | +| global.privileged | privileged | Depends on the chart | | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | +| global.proxy | proxy | `""` | | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.nrStaging | nrStaging | `false` | | Send the metrics to the staging backend. Requires a valid staging license key | +| global.verboseLog | verboseLog | `false` | | Sets the debug/trace logs to this integration or all integrations if it is set globally | + +### Further information + +#### 1. Merged + +Merged means that the values from global are not replaced by the local ones. Think in this example: +```yaml +global: + labels: + global: global + hostNetwork: true + nodeSelector: + global: global + +labels: + local: local +nodeSelector: + local: local +hostNetwork: false +``` + +This values will template `hostNetwork` to `false`, a map of labels `{ "global": "global", "local": "local" }` and a `nodeSelector` with +`{ "local": "local" }`. + +As Helm by default merges all the maps it could be confusing that we have two behaviors (merging `labels` and replacing `nodeSelector`) +the `values` from global to local. This is the rationale behind this: +* `hostNetwork` is templated to `false` because is overriding the value defined globally. +* `labels` are merged because the user may want to label all the New Relic pods at once and label other solution pods differently for + clarity' sake. +* `nodeSelector` does not merge as `labels` because could make it harder to overwrite/delete a selector that comes from global because + of the logic that Helm follows merging maps. + + +#### 2. Fine grain registries + +Some charts only have 1 image while others that can have 2 or more images. The local path for the registry can change depending +on the chart itself. + +As this is mostly unique per helm chart, you should take a look to the chart's values table (or directly to the `values.yaml` file to see all the +images that you can change. + +This should only be needed if you have an advanced setup that forces you to have granularity enough to force a proxy/cache registry per integration. + + + +#### 3. Privileged mode + +By default, from the common library, the privileged mode is set to false. But most of the helm charts require this to be true to fetch more +metrics so could see a true in some charts. The consequences of the privileged mode differ from one chart to another so for each chart that +honors the privileged mode toggle should be a section in the README explaining which is the behavior with it enabled or disabled. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_affinity.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_affinity.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod affinity */ -}} +{{- define "newrelic.common.affinity" -}} + {{- if .Values.affinity -}} + {{- toYaml .Values.affinity -}} + {{- else if .Values.global -}} + {{- if .Values.global.affinity -}} + {{- toYaml .Values.global.affinity -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_agent-config.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..9c32861a0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,26 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +log: + level: trace +{{- end }} + +{{- if (include "newrelic.common.nrStaging" . ) }} +staging: true +{{- end }} + +{{- with include "newrelic.common.proxy" . }} +proxy: {{ . | quote }} +{{- end }} + +{{- with include "newrelic.common.fedramp.enabled" . }} +fedramp: {{ . }} +{{- end }} + +{{- with fromYaml ( include "newrelic.common.customAttributes" . ) }} +custom_attributes: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_cluster.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_cluster.tpl @@ -0,0 +1,15 @@ +{{/* +Return the cluster +*/}} +{{- define "newrelic.common.cluster" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.cluster -}} + {{- .Values.cluster -}} +{{- else if $global.cluster -}} + {{- $global.cluster -}} +{{- else -}} + {{ fail "There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required." }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_custom-attributes.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_custom-attributes.tpl @@ -0,0 +1,17 @@ +{{/* +This will render custom attributes as a YAML ready to be templated or be used with `fromYaml`. +*/}} +{{- define "newrelic.common.customAttributes" -}} +{{- $customAttributes := dict -}} + +{{- $global := index .Values "global" | default dict -}} +{{- if $global.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes $global.customAttributes -}} +{{- end -}} + +{{- if .Values.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes .Values.customAttributes -}} +{{- end -}} + +{{- toYaml $customAttributes -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_dnsconfig.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_dnsconfig.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod dnsConfig */ -}} +{{- define "newrelic.common.dnsConfig" -}} + {{- if .Values.dnsConfig -}} + {{- toYaml .Values.dnsConfig -}} + {{- else if .Values.global -}} + {{- if .Values.global.dnsConfig -}} + {{- toYaml .Values.global.dnsConfig -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_fedramp.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_fedramp.tpl @@ -0,0 +1,25 @@ +{{- /* Defines the fedRAMP flag */ -}} +{{- define "newrelic.common.fedramp.enabled" -}} + {{- if .Values.fedramp -}} + {{- if .Values.fedramp.enabled -}} + {{- .Values.fedramp.enabled -}} + {{- end -}} + {{- else if .Values.global -}} + {{- if .Values.global.fedramp -}} + {{- if .Values.global.fedramp.enabled -}} + {{- .Values.global.fedramp.enabled -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{- /* Return FedRAMP value directly ready to be templated */ -}} +{{- define "newrelic.common.fedramp.enabled.value" -}} +{{- if include "newrelic.common.fedramp.enabled" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_hostnetwork.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_hostnetwork.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the hostNetwork toggle. +This helper allows to override the global `.global.hostNetwork` with the value of `.hostNetwork`. +Returns "true" if `hostNetwork` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.hostNetwork" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- /* +`get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs + +We also want only to return when this is true, returning `false` here will template "false" (string) when doing +an `(include "newrelic.common.hostNetwork" .)`, which is not an "empty string" so it is `true` if it is used +as an evaluation somewhere else. +*/ -}} +{{- if get .Values "hostNetwork" | kindIs "bool" -}} + {{- if .Values.hostNetwork -}} + {{- .Values.hostNetwork -}} + {{- end -}} +{{- else if get $global "hostNetwork" | kindIs "bool" -}} + {{- if $global.hostNetwork -}} + {{- $global.hostNetwork -}} + {{- end -}} +{{- end -}} +{{- end -}} + + +{{- /* +Abstraction of the hostNetwork toggle. +This helper abstracts the function "newrelic.common.hostNetwork" to return true or false directly. +*/ -}} +{{- define "newrelic.common.hostNetwork.value" -}} +{{- if include "newrelic.common.hostNetwork" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_images.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..d4fb43290 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_images.tpl @@ -0,0 +1,94 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "defaultRegistry" .defaultRegistry "context" .context ) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic.common.images.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image registry +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} +{{- $globalRegistry := "" -}} +{{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- with .context.Values.global.images.registry -}} + {{- $globalRegistry = . -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- $localRegistry := "" -}} +{{- if .imageRoot.registry -}} + {{- $localRegistry = .imageRoot.registry -}} +{{- end -}} + +{{- $registry := $localRegistry | default $globalRegistry | default .defaultRegistry -}} +{{- if $registry -}} + {{- $registry -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image repository +{{ include "newrelic.common.images.repository" .Values.path.to.the.image }} +*/ -}} +{{- define "newrelic.common.images.repository" -}} + {{- .repository -}} +{{- end -}} + + + +{{- /* +Return the proper image tag +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.tag" -}} + {{- .imageRoot.tag | default .context.Chart.AppVersion | toString -}} +{{- end -}} + + + +{{- /* +Return the proper Image Pull Registry Secret Names evaluating values as templates +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.path.to.the.images.pullSecrets1, .Values.path.to.the.images.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- if .context.Values.global.images.pullSecrets -}} + {{- range .context.Values.global.images.pullSecrets -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- range .pullSecrets -}} + {{- if not (empty .) -}} + {{- range . -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if $flatlist -}} + {{- toYaml $flatlist -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_insights.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_insights.tpl new file mode 100644 index 000000000..895c37732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_insights.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the Insights Key. +*/}} +{{- define "newrelic.common.insightsKey.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "insightskey" ) -}} +{{- include "newrelic.common.insightsKey._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +*/}} +{{- define "newrelic.common.insightsKey.secretKeyName" -}} +{{- include "newrelic.common.insightsKey._customSecretKey" . | default "insightsKey" -}} +{{- end -}} + +{{/* +Return local insightsKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._licenseKey" -}} +{{- if .Values.insightsKey -}} + {{- .Values.insightsKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.insightsKey -}} + {{- .Values.global.insightsKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the Insights Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretName" -}} +{{- if .Values.customInsightsKeySecretName -}} + {{- .Values.customInsightsKeySecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretName -}} + {{- .Values.global.customInsightsKeySecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretKey" -}} +{{- if .Values.customInsightsKeySecretKey -}} + {{- .Values.customInsightsKeySecretKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretKey }} + {{- .Values.global.customInsightsKeySecretKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_insights_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_insights_secret.yaml.tpl new file mode 100644 index 000000000..556caa6ca --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_insights_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the insights key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.insightsKey.secret" }} +{{- if not (include "newrelic.common.insightsKey._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.insightsKey._licenseKey" .) }} + {{- fail "You must specify a insightsKey or a customInsightsSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.insightsKey.secretKeyName" . }}: {{ include "newrelic.common.insightsKey._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_labels.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_labels.tpl @@ -0,0 +1,54 @@ +{{/* +This will render the labels that should be used in all the manifests used by the helm chart. +*/}} +{{- define "newrelic.common.labels" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- $chart := dict "helm.sh/chart" (include "newrelic.common.naming.chart" . ) -}} +{{- $managedBy := dict "app.kubernetes.io/managed-by" .Release.Service -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $labels := mustMergeOverwrite $chart $managedBy $selectorLabels -}} +{{- if .Chart.AppVersion -}} +{{- $labels = mustMergeOverwrite $labels (dict "app.kubernetes.io/version" .Chart.AppVersion) -}} +{{- end -}} + +{{- $globalUserLabels := $global.labels | default dict -}} +{{- $localUserLabels := .Values.labels | default dict -}} + +{{- $labels = mustMergeOverwrite $labels $globalUserLabels $localUserLabels -}} + +{{- toYaml $labels -}} +{{- end -}} + + + +{{/* +This will render the labels that should be used in deployments/daemonsets template pods as a selector. +*/}} +{{- define "newrelic.common.labels.selectorLabels" -}} +{{- $name := dict "app.kubernetes.io/name" ( include "newrelic.common.naming.name" . ) -}} +{{- $instance := dict "app.kubernetes.io/instance" .Release.Name -}} + +{{- $selectorLabels := mustMergeOverwrite $name $instance -}} + +{{- toYaml $selectorLabels -}} +{{- end }} + + + +{{/* +Pod labels +*/}} +{{- define "newrelic.common.labels.podLabels" -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $global := index .Values "global" | default dict -}} +{{- $globalPodLabels := $global.podLabels | default dict }} + +{{- $localPodLabels := .Values.podLabels | default dict }} + +{{- $podLabels := mustMergeOverwrite $selectorLabels $globalPodLabels $localPodLabels -}} + +{{- toYaml $podLabels -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..647b4ff43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "license" ) -}} +{{- include "newrelic.common.license._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +*/}} +{{- define "newrelic.common.license.secretKeyName" -}} +{{- include "newrelic.common.license._customSecretKey" . | default "licenseKey" -}} +{{- end -}} + +{{/* +Return local licenseKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._licenseKey" -}} +{{- if .Values.licenseKey -}} + {{- .Values.licenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.licenseKey -}} + {{- .Values.global.licenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the License Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretName" -}} +{{- if .Values.customSecretName -}} + {{- .Values.customSecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretName -}} + {{- .Values.global.customSecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretKey" -}} +{{- if .Values.customSecretLicenseKey -}} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the license key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.license.secret" }} +{{- if not (include "newrelic.common.license._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.license._licenseKey" .) }} + {{- fail "You must specify a licenseKey or a customSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.license.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.license.secretKeyName" . }}: {{ include "newrelic.common.license._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_low-data-mode.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_low-data-mode.tpl @@ -0,0 +1,26 @@ +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..19fa92648 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_naming.tpl @@ -0,0 +1,73 @@ +{{/* +This is an function to be called directly with a string just to truncate strings to +63 chars because some Kubernetes name fields are limited to that. +*/}} +{{- define "newrelic.common.naming.truncateToDNS" -}} +{{- . | trunc 63 | trimSuffix "-" }} +{{- end }} + + + +{{- /* +Given a name and a suffix returns a 'DNS Valid' which always include the suffix, truncating the name if needed. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If suffix is too long it gets truncated but it always takes precedence over name, so a 63 chars suffix would suppress the name. +Usage: +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "" "suffix" "my-suffix" ) }} +*/ -}} +{{- define "newrelic.common.naming.truncateToDNSWithSuffix" -}} +{{- $suffix := (include "newrelic.common.naming.truncateToDNS" .suffix) -}} +{{- $maxLen := (max (sub 63 (add1 (len $suffix))) 0) -}} {{- /* We prepend "-" to the suffix so an additional character is needed */ -}} + +{{- $newName := .name | trunc ($maxLen | int) | trimSuffix "-" -}} +{{- if $newName -}} +{{- printf "%s-%s" $newName $suffix -}} +{{- else -}} +{{ $suffix }} +{{- end -}} + +{{- end -}} + + + +{{/* +Expand the name of the chart. +Uses the Chart name by default if nameOverride is not set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.name" -}} +{{- $name := .Values.nameOverride | default .Chart.Name -}} +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end }} + + + +{{/* +Create a default fully qualified app name. +By default the full name will be "" just in if it has the chart name included in that, if not +it will be concatenated like "-". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.fullname" -}} +{{- $name := include "newrelic.common.naming.name" . -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} + +{{- end -}} + + + +{{/* +Create chart name and version as used by the chart label. +This function should not be used for naming objects. Use "common.naming.{name,fullname}" instead. +*/}} +{{- define "newrelic.common.naming.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_nodeselector.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_nodeselector.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod nodeSelector */ -}} +{{- define "newrelic.common.nodeSelector" -}} + {{- if .Values.nodeSelector -}} + {{- toYaml .Values.nodeSelector -}} + {{- else if .Values.global -}} + {{- if .Values.global.nodeSelector -}} + {{- toYaml .Values.global.nodeSelector -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_priority-class-name.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_priority-class-name.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the pod priorityClassName */ -}} +{{- define "newrelic.common.priorityClassName" -}} + {{- if .Values.priorityClassName -}} + {{- .Values.priorityClassName -}} + {{- else if .Values.global -}} + {{- if .Values.global.priorityClassName -}} + {{- .Values.global.priorityClassName -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_privileged.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_privileged.tpl @@ -0,0 +1,28 @@ +{{- /* +This is a helper that returns whether the chart should assume the user is fine deploying privileged pods. +*/ -}} +{{- define "newrelic.common.privileged" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists. */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values "privileged" | kindIs "bool" -}} + {{- if .Values.privileged -}} + {{- .Values.privileged -}} + {{- end -}} +{{- else if get $global "privileged" | kindIs "bool" -}} + {{- if $global.privileged -}} + {{- $global.privileged -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* Return directly "true" or "false" based in the exist of "newrelic.common.privileged" */ -}} +{{- define "newrelic.common.privileged.value" -}} +{{- if include "newrelic.common.privileged" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_proxy.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_proxy.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the proxy */ -}} +{{- define "newrelic.common.proxy" -}} + {{- if .Values.proxy -}} + {{- .Values.proxy -}} + {{- else if .Values.global -}} + {{- if .Values.global.proxy -}} + {{- .Values.global.proxy -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_security-context.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_security-context.tpl @@ -0,0 +1,23 @@ +{{- /* Defines the container securityContext context */ -}} +{{- define "newrelic.common.securityContext.container" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.containerSecurityContext -}} + {{- toYaml .Values.containerSecurityContext -}} +{{- else if $global.containerSecurityContext -}} + {{- toYaml $global.containerSecurityContext -}} +{{- end -}} +{{- end -}} + + + +{{- /* Defines the pod securityContext context */ -}} +{{- define "newrelic.common.securityContext.pod" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.podSecurityContext -}} + {{- toYaml .Values.podSecurityContext -}} +{{- else if $global.podSecurityContext -}} + {{- toYaml $global.podSecurityContext -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_serviceaccount.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..2d352f6ea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_serviceaccount.tpl @@ -0,0 +1,90 @@ +{{- /* Defines if the service account has to be created or not */ -}} +{{- define "newrelic.common.serviceAccount.create" -}} +{{- $valueFound := false -}} + +{{- /* Look for a global creation of a service account */ -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "create" | kindIs "bool") -}} + {{- $valueFound = true -}} + {{- if .Values.serviceAccount.create -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.serviceAccount.name" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.serviceAccount.create -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Look for a local creation of a service account */ -}} +{{- if not $valueFound -}} + {{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} + {{- $global := index .Values "global" | default dict -}} + {{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "create" | kindIs "bool" -}} + {{- $valueFound = true -}} + {{- if $global.serviceAccount.create -}} + {{- $global.serviceAccount.create -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* In case no serviceAccount value has been found, default to "true" */ -}} +{{- if not $valueFound -}} +true +{{- end -}} +{{- end -}} + + + +{{- /* Defines the name of the service account */ -}} +{{- define "newrelic.common.serviceAccount.name" -}} +{{- $localServiceAccount := "" -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "name" | kindIs "string") -}} + {{- $localServiceAccount = .Values.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := "" -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "name" | kindIs "string" -}} + {{- $globalServiceAccount = $global.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- if (include "newrelic.common.serviceAccount.create" .) -}} + {{- $localServiceAccount | default $globalServiceAccount | default (include "newrelic.common.naming.fullname" .) -}} +{{- else -}} + {{- $localServiceAccount | default $globalServiceAccount | default "default" -}} +{{- end -}} +{{- end -}} + + + +{{- /* Merge the global and local annotations for the service account */ -}} +{{- define "newrelic.common.serviceAccount.annotations" -}} +{{- $localServiceAccount := dict -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if get .Values.serviceAccount "annotations" -}} + {{- $localServiceAccount = .Values.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := dict -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "annotations" -}} + {{- $globalServiceAccount = $global.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $merged := mustMergeOverwrite $globalServiceAccount $localServiceAccount -}} + +{{- if $merged -}} + {{- toYaml $merged -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_staging.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_staging.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the nrStaging toggle. +This helper allows to override the global `.global.nrStaging` with the value of `.nrStaging`. +Returns "true" if `nrStaging` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.nrStaging" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "nrStaging" | kindIs "bool") -}} + {{- if .Values.nrStaging -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.nrStaging" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.nrStaging -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "nrStaging" | kindIs "bool" -}} + {{- if $global.nrStaging -}} + {{- $global.nrStaging -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Returns "true" of "false" directly instead of empty string (Helm falsiness) based on the exit of "newrelic.common.nrStaging" +*/ -}} +{{- define "newrelic.common.nrStaging.value" -}} +{{- if include "newrelic.common.nrStaging" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_tolerations.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_tolerations.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod tolerations */ -}} +{{- define "newrelic.common.tolerations" -}} + {{- if .Values.tolerations -}} + {{- toYaml .Values.tolerations -}} + {{- else if .Values.global -}} + {{- if .Values.global.tolerations -}} + {{- toYaml .Values.global.tolerations -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_verbose-log.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_verbose-log.tpl @@ -0,0 +1,54 @@ +{{- /* +Abstraction of the verbose toggle. +This helper allows to override the global `.global.verboseLog` with the value of `.verboseLog`. +Returns "true" if `verbose` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.verboseLog" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "verboseLog" | kindIs "bool") -}} + {{- if .Values.verboseLog -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.verboseLog" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.verboseLog -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "verboseLog" | kindIs "bool" -}} + {{- if $global.verboseLog -}} + {{- $global.verboseLog -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return true or false directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsBoolean" -}} +{{- if include "newrelic.common.verboseLog" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return 1 or 0 directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsInt" -}} +{{- if include "newrelic.common.verboseLog" . -}} +1 +{{- else -}} +0 +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/charts/common-library/values.yaml @@ -0,0 +1 @@ +# values are not needed for the library chart, however this file is still needed for helm lint to work. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/ci/test-values.yaml new file mode 100644 index 000000000..f0f9be1f9 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/ci/test-values.yaml @@ -0,0 +1,14 @@ +global: + cluster: test-cluster + +personalAPIKey: "a21321" +verboseLog: false + +config: + accountID: 111 + region: EU + nrdbClientTimeoutSeconds: 30 + +image: + repository: e2e/newrelic-metrics-adapter + tag: "test" # Defaults to AppVersion diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/_helpers.tpl new file mode 100644 index 000000000..6a5f76503 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/_helpers.tpl @@ -0,0 +1,57 @@ +{{/* vim: set filetype=mustache: */}} + +{{- /* Allow to change pod defaults dynamically based if we are running in privileged mode or not */ -}} +{{- define "newrelic-k8s-metrics-adapter.securityContext.pod" -}} +{{- if include "newrelic.common.securityContext.pod" . -}} +{{- include "newrelic.common.securityContext.pod" . -}} +{{- else -}} +fsGroup: 1001 +runAsUser: 1001 +runAsGroup: 1001 +{{- end -}} +{{- end -}} + + + +{{/* +Select a value for the region +When this value is empty the New Relic client region will be the default 'US' +*/}} +{{- define "newrelic-k8s-metrics-adapter.region" -}} +{{- if .Values.config.region -}} + {{- .Values.config.region | upper -}} +{{- else if (include "newrelic.common.nrStaging" .) -}} +Staging +{{- else if hasPrefix "eu" (include "newrelic.common.license._licenseKey" .) -}} +EU +{{- end -}} +{{- end -}} + + + +{{- /* +Naming helpers +*/ -}} +{{- define "newrelic-k8s-metrics-adapter.name.apiservice" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "apiservice") }} +{{- end -}} + +{{- define "newrelic-k8s-metrics-adapter.name.apiservice.serviceAccount" -}} +{{- if include "newrelic.common.serviceAccount.create" . -}} + {{- include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "apiservice") -}} +{{- else -}} + {{- include "newrelic.common.serviceAccount.name" . -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-k8s-metrics-adapter.name.apiservice-create" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "apiservice-create") }} +{{- end -}} + +{{- define "newrelic-k8s-metrics-adapter.name.apiservice-patch" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "apiservice-patch") }} +{{- end -}} + +{{- define "newrelic-k8s-metrics-adapter.name.hpa-controller" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "hpa-controller") }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/adapter-clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/adapter-clusterrolebinding.yaml new file mode 100644 index 000000000..40bcba8b6 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/adapter-clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "newrelic.common.naming.fullname" . }}:system:auth-delegator + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/adapter-rolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/adapter-rolebinding.yaml new file mode 100644 index 000000000..afb5d2d55 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/adapter-rolebinding.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: kube-system + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: +- kind: ServiceAccount + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/apiservice.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/apiservice.yaml new file mode 100644 index 000000000..8f01b6407 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/apiservice.yaml @@ -0,0 +1,19 @@ +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1beta1.external.metrics.k8s.io + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +{{- if .Values.certManager.enabled }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-root-cert" .Release.Namespace (include "newrelic.common.naming.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-root-cert" .Release.Namespace (include "newrelic.common.naming.fullname" .) | quote }} +{{- end }} +spec: + service: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + group: external.metrics.k8s.io + version: v1beta1 + groupPriorityMinimum: 100 + versionPriority: 100 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrole.yaml new file mode 100644 index 000000000..5c364eb37 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrole.yaml @@ -0,0 +1,26 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + - apiGroups: + - apiregistration.k8s.io + resources: + - apiservices + verbs: + - get + - update +{{- if .Values.rbac.pspEnabled }} + - apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrolebinding.yaml new file mode 100644 index 000000000..8aa95792e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrolebinding.yaml @@ -0,0 +1,19 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} +subjects: + - kind: ServiceAccount + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice.serviceAccount" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-createSecret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-createSecret.yaml new file mode 100644 index 000000000..6cf89b79e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-createSecret.yaml @@ -0,0 +1,55 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice-create" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + template: + metadata: + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice-create" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 8 }} + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.image.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + containers: + - name: create + image: {{ include "newrelic.common.images.image" ( dict "defaultRegistry" "registry.k8s.io" "imageRoot" .Values.apiServicePatchJob.image "context" .) }} + imagePullPolicy: {{ .Values.apiServicePatchJob.image.pullPolicy }} + args: + - create + - --host={{ include "newrelic.common.naming.fullname" . }},{{ include "newrelic.common.naming.fullname" . }}.{{ .Release.Namespace }}.svc + - --namespace={{ .Release.Namespace }} + - --secret-name={{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} + - --cert-name=tls.crt + - --key-name=tls.key + {{- with .Values.apiServicePatchJob.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.apiServicePatchJob.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + serviceAccountName: {{ include "newrelic-k8s-metrics-adapter.name.apiservice.serviceAccount" . }} + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-patchAPIService.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-patchAPIService.yaml new file mode 100644 index 000000000..9d651c210 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-patchAPIService.yaml @@ -0,0 +1,53 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice-patch" . }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + template: + metadata: + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice-patch" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 8 }} + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.image.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + containers: + - name: patch + image: {{ include "newrelic.common.images.image" ( dict "defaultRegistry" "registry.k8s.io" "imageRoot" .Values.apiServicePatchJob.image "context" .) }} + imagePullPolicy: {{ .Values.apiServicePatchJob.image.pullPolicy }} + args: + - patch + - --namespace={{ .Release.Namespace }} + - --secret-name={{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} + - --apiservice-name=v1beta1.external.metrics.k8s.io + {{- with .Values.apiServicePatchJob.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.apiServicePatchJob.volumes }} + volumes: + {{- toYaml . | nindent 6 }} + {{- end }} + restartPolicy: OnFailure + serviceAccountName: {{ include "newrelic-k8s-metrics-adapter.name.apiservice.serviceAccount" . }} + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/psp.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/psp.yaml new file mode 100644 index 000000000..1dd6bc1a6 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/psp.yaml @@ -0,0 +1,49 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled) (.Values.rbac.pspEnabled)) }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + privileged: false + # Required to prevent escalations to root. + # allowPrivilegeEscalation: false + # This is redundant with non-root + disallow privilege escalation, + # but we can provide it for defense in depth. + # requiredDropCapabilities: + # - ALL + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + - 'persistentVolumeClaim' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Permits the container to run with root privileges as well. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 0 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/role.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/role.yaml new file mode 100644 index 000000000..1e870e082 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/role.yaml @@ -0,0 +1,20 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/rolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/rolebinding.yaml new file mode 100644 index 000000000..cbe8bdb72 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/rolebinding.yaml @@ -0,0 +1,20 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} +subjects: + - kind: ServiceAccount + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice.serviceAccount" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/serviceaccount.yaml new file mode 100644 index 000000000..68a3cfd73 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- $createServiceAccount := include "newrelic.common.serviceAccount.create" . -}} +{{- if (and $createServiceAccount (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic-k8s-metrics-adapter.name.apiservice.serviceAccount" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + # When hooks are sorted by weight and name, kind order gets overwritten, + # then this serviceAccount doesn't get created before dependent objects causing a failure. + # This weight is set, forcing it always to get created before the other objects. + # We submitted this PR to fix the issue: https://github.com/helm/helm/pull/10787 + "helm.sh/hook-weight": "-1" + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/configmap.yaml new file mode 100644 index 000000000..8e88ad59e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/configmap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + config.yaml: | + accountID: {{ .Values.config.accountID | required "config.accountID is required" }} + {{- with (include "newrelic-k8s-metrics-adapter.region" .) }} + region: {{ . }} + {{- end }} + cacheTTLSeconds: {{ .Values.config.cacheTTLSeconds | default "0" }} + {{- with .Values.config.externalMetrics }} + externalMetrics: + {{- toYaml . | nindent 6 }} + {{- end }} + nrdbClientTimeoutSeconds: {{ .Values.config.nrdbClientTimeoutSeconds | default "30" }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/deployment.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/deployment.yaml new file mode 100644 index 000000000..1b96459a5 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/deployment.yaml @@ -0,0 +1,113 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- if .Values.podAnnotations }} + {{- toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} + {{- with include "newrelic-k8s-metrics-adapter.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.image.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + containers: + - name: {{ include "newrelic.common.naming.name" . }} + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.image "context" .) }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + {{- with include "newrelic.common.securityContext.container" . }} + securityContext: + {{- . | nindent 10 }} + {{- end }} + args: + - --tls-cert-file=/tmp/k8s-metrics-adapter/serving-certs/tls.crt + - --tls-private-key-file=/tmp/k8s-metrics-adapter/serving-certs/tls.key + {{- if .Values.verboseLog }} + - --v=10 + {{- else }} + - --v=1 + {{- end }} + readinessProbe: + httpGet: + scheme: HTTPS + path: /healthz + port: 6443 + initialDelaySeconds: 1 + {{- if .Values.resources }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + {{- end }} + env: + - name: CLUSTER_NAME + value: {{ include "newrelic.common.cluster" . }} + - name: NEWRELIC_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.naming.fullname" . }} + key: personalAPIKey + {{- with (include "newrelic.common.proxy" .) }} + - name: HTTPS_PROXY + value: {{ . }} + {{- end }} + {{- with .Values.extraEnv }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.extraEnvFrom }} + envFrom: {{ toYaml . | nindent 8 }} + {{- end }} + volumeMounts: + - name: tls-key-cert-pair + mountPath: /tmp/k8s-metrics-adapter/serving-certs/ + - name: config + mountPath: /etc/newrelic/adapter/ + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: tls-key-cert-pair + secret: + secretName: {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} + - name: config + configMap: + name: {{ include "newrelic.common.naming.fullname" . }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 8 }} + {{- end }} + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrole.yaml new file mode 100644 index 000000000..402fece01 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrole.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "newrelic.common.naming.fullname" . }}:external-metrics + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: +- apiGroups: + - external.metrics.k8s.io + resources: + - "*" + verbs: + - list + - get + - watch diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrolebinding.yaml new file mode 100644 index 000000000..390fab452 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "newrelic-k8s-metrics-adapter.name.hpa-controller" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic.common.naming.fullname" . }}:external-metrics +subjects: +- kind: ServiceAccount + name: horizontal-pod-autoscaler + namespace: kube-system diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/secret.yaml new file mode 100644 index 000000000..09a70ab65 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/secret.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +type: Opaque +stringData: + personalAPIKey: {{ .Values.personalAPIKey | required "personalAPIKey must be set" | quote }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/service.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/service.yaml new file mode 100644 index 000000000..82015830c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + ports: + - port: 443 + targetPort: 6443 + selector: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 4 }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/serviceaccount.yaml new file mode 100644 index 000000000..b1e74523e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- if include "newrelic.common.serviceAccount.annotations" . }} + annotations: + {{- include "newrelic.common.serviceAccount.annotations" . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/apiservice_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/apiservice_test.yaml new file mode 100644 index 000000000..086160edc --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/apiservice_test.yaml @@ -0,0 +1,22 @@ +suite: test naming helper for APIService's certmanager annotations and service name +templates: + - templates/apiservice/apiservice.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: Annotations are correctly defined + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 11111111 + certManager: + enabled: true + asserts: + - matchRegex: + path: metadata.annotations["certmanager.k8s.io/inject-ca-from"] + pattern: ^my-namespace\/.*-root-cert + - matchRegex: + path: metadata.annotations["cert-manager.io/inject-ca-from"] + pattern: ^my-namespace\/.*-root-cert diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/common_extra_naming_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/common_extra_naming_test.yaml new file mode 100644 index 000000000..82098ba1c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/common_extra_naming_test.yaml @@ -0,0 +1,27 @@ +suite: test naming helpers +templates: + - templates/adapter-clusterrolebinding.yaml + - templates/hpa-clusterrole.yaml + - templates/hpa-clusterrolebinding.yaml + - templates/apiservice/job-patch/clusterrole.yaml + - templates/apiservice/job-patch/clusterrolebinding.yaml + - templates/apiservice/job-patch/job-createSecret.yaml + - templates/apiservice/job-patch/job-patchAPIService.yaml + - templates/apiservice/job-patch/psp.yaml + - templates/apiservice/job-patch/rolebinding.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: default values has its name correctly defined + set: + cluster: test-cluster + personalAPIKey: 21321 + config: + accountID: 11111111 + rbac: + pspEnabled: true + asserts: + - matchRegex: + path: metadata.name + pattern: ^.*(-apiservice|-hpa-controller|:external-metrics|:system:auth-delegator) diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/configmap_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/configmap_test.yaml new file mode 100644 index 000000000..90b8798a7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/configmap_test.yaml @@ -0,0 +1,104 @@ +suite: test configmap region helper and externalMetrics +templates: + - templates/configmap.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: has the correct region when defined in local values + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - equal: + path: data["config.yaml"] + value: | + accountID: 111 + region: A-REGION + cacheTTLSeconds: 30 + nrdbClientTimeoutSeconds: 30 + - it: has the correct region when global staging + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + global: + nrStaging: true + asserts: + - equal: + path: data["config.yaml"] + value: | + accountID: 111 + region: Staging + cacheTTLSeconds: 30 + nrdbClientTimeoutSeconds: 30 + - it: has the correct region when global values and licenseKey is from eu + set: + personalAPIKey: 21321 + licenseKey: eu-whatever + cluster: test-cluster + config: + accountID: 111 + global: + aRandomGlobalValue: true + asserts: + - equal: + path: data["config.yaml"] + value: | + accountID: 111 + region: EU + cacheTTLSeconds: 30 + nrdbClientTimeoutSeconds: 30 + - it: has the correct region when no global values exist and licenseKey is from eu + set: + personalAPIKey: 21321 + cluster: test-cluster + licenseKey: eu-whatever + config: + accountID: 111 + asserts: + - equal: + path: data["config.yaml"] + value: | + accountID: 111 + region: EU + cacheTTLSeconds: 30 + nrdbClientTimeoutSeconds: 30 + - it: has no region when not defined and licenseKey is not from eu + set: + personalAPIKey: 21321 + cluster: test-cluster + licenseKey: us-whatever + config: + accountID: 111 + asserts: + - equal: + path: data["config.yaml"] + value: | + accountID: 111 + cacheTTLSeconds: 30 + nrdbClientTimeoutSeconds: 30 + - it: has externalMetrics when defined + set: + personalAPIKey: 21321 + cluster: test-cluster + licenseKey: us-whatever + config: + accountID: 111 + externalMetrics: + nginx_average_requests: + query: "FROM Metric SELECT average(nginx.server.net.requestsPerSecond)" + asserts: + - equal: + path: data["config.yaml"] + value: | + accountID: 111 + cacheTTLSeconds: 30 + externalMetrics: + nginx_average_requests: + query: FROM Metric SELECT average(nginx.server.net.requestsPerSecond) + nrdbClientTimeoutSeconds: 30 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/deployment_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/deployment_test.yaml new file mode 100644 index 000000000..7a1898790 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/deployment_test.yaml @@ -0,0 +1,99 @@ +suite: test deployent images +release: + name: my-release + namespace: my-namespace +tests: + - it: has the correct image + set: + global: + cluster: test-cluster + personalAPIKey: 21321 + image: + repository: newrelic/newrelic-k8s-metrics-adapter + tag: "latest" + pullSecrets: + - name: regsecret + config: + accountID: 111 + region: A-REGION + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: ^.*newrelic/newrelic-k8s-metrics-adapter:latest + template: templates/deployment.yaml + - equal: + path: spec.template.spec.imagePullSecrets + value: + - name: regsecret + template: templates/deployment.yaml + - it: correctly uses the cluster helper + set: + personalAPIKey: 21321 + config: + accountID: 111 + region: A-REGION + cluster: a-cluster + asserts: + - equal: + path: spec.template.spec.containers[0].env[0].value + value: a-cluster + template: templates/deployment.yaml + - it: correctly uses common.securityContext.podDefaults + set: + personalAPIKey: 21321 + config: + accountID: 111 + region: A-REGION + cluster: a-cluster + asserts: + - equal: + path: spec.template.spec.securityContext + value: + fsGroup: 1001 + runAsGroup: 1001 + runAsUser: 1001 + template: templates/deployment.yaml + - it: correctly uses common.proxy + set: + personalAPIKey: 21321 + config: + accountID: 111 + region: A-REGION + cluster: a-cluster + proxy: localhost:1234 + asserts: + - equal: + path: spec.template.spec.containers[0].env[2].value + value: localhost:1234 + template: templates/deployment.yaml + + - it: has a linux node selector by default + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + template: templates/deployment.yaml + + - it: has a linux node selector and additional selectors + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + nodeSelector: + aCoolTestLabel: aCoolTestValue + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + aCoolTestLabel: aCoolTestValue + template: templates/deployment.yaml diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/hpa_clusterrolebinding_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/hpa_clusterrolebinding_test.yaml new file mode 100644 index 000000000..4fba87fbe --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/hpa_clusterrolebinding_test.yaml @@ -0,0 +1,18 @@ +suite: test naming helper for clusterRolebBinding roleRef +templates: + - templates/hpa-clusterrolebinding.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: roleRef.name has its name correctly defined + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - matchRegex: + path: roleRef.name + pattern: ^.*:external-metrics diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_cluster_rolebinding_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_cluster_rolebinding_test.yaml new file mode 100644 index 000000000..dd582313e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_cluster_rolebinding_test.yaml @@ -0,0 +1,22 @@ +suite: test job-patch RoleBinding and ClusterRoleBinding rendering and roleRef/Subjects names +templates: + - templates/apiservice/job-patch/rolebinding.yaml + - templates/apiservice/job-patch/clusterrolebinding.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: roleRef apiGroup and Subjets are correctly defined + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - matchRegex: + path: roleRef.name + pattern: ^.*-apiservice + - matchRegex: + path: subjects[0].name + pattern: ^.*-apiservice diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_clusterrole_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_clusterrole_test.yaml new file mode 100644 index 000000000..33a1eaa73 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_clusterrole_test.yaml @@ -0,0 +1,20 @@ +suite: test job-patch clusterRole rule resourceName and rendering +templates: + - templates/apiservice/job-patch/clusterrole.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: PodSecurityPolicy rule resourceName is correctly defined + set: + rbac: + pspEnabled: true + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - matchRegex: + path: rules[1].resourceNames[0] + pattern: ^.*-apiservice diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_common_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_common_test.yaml new file mode 100644 index 000000000..91cd791d1 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_common_test.yaml @@ -0,0 +1,27 @@ +suite: test labels and rendering for job-batch objects +templates: + - templates/apiservice/job-patch/clusterrole.yaml + - templates/apiservice/job-patch/clusterrolebinding.yaml + - templates/apiservice/job-patch/job-createSecret.yaml + - templates/apiservice/job-patch/job-patchAPIService.yaml + - templates/apiservice/job-patch/psp.yaml + - templates/apiservice/job-patch/role.yaml + - templates/apiservice/job-patch/rolebinding.yaml + - templates/apiservice/job-patch/serviceaccount.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: If customTLSCertificate and Certmanager enabled do not render + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + customTLSCertificate: a-tls-cert + certManager: + enabled: true + asserts: + - hasDocuments: + count: 0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_createsecret_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_createsecret_test.yaml new file mode 100644 index 000000000..6db79234f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_createsecret_test.yaml @@ -0,0 +1,47 @@ +suite: test naming helper for job-createSecret +templates: + - templates/apiservice/job-patch/job-createSecret.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: spec metadata name is is correctly defined + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - equal: + path: spec.template.metadata.name + value: my-release-newrelic-k8s-metrics-adapter-apiservice-create + - it: container args are correctly defined + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - matchRegex: + path: spec.template.spec.containers[0].args[1] + pattern: --host=.*,.*\.my-namespace.svc + - matchRegex: + path: spec.template.spec.containers[0].args[3] + pattern: --secret-name=.*-apiservice + - it: has the correct image + set: + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + personalAPIKey: 21321 + apiServicePatchJob: + image: + repository: registry.k8s.io/ingress-nginx/kube-webhook-certgen + tag: "latest" + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: ^.*registry.k8s.io/ingress-nginx/kube-webhook-certgen:latest diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_patchapiservice_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_patchapiservice_test.yaml new file mode 100644 index 000000000..0be083313 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_patchapiservice_test.yaml @@ -0,0 +1,56 @@ +suite: test naming helper for job-patchAPIService +templates: + - templates/apiservice/job-patch/job-patchAPIService.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: spec metadata name is is correctly defined + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - matchRegex: + path: spec.template.metadata.name + pattern: .*-apiservice-patch$ + - it: container args are correctly defined + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - matchRegex: + path: spec.template.spec.containers[0].args[2] + pattern: ^--secret-name=.*-apiservice + + - it: serviceAccountName is correctly defined + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - matchRegex: + path: spec.template.spec.serviceAccountName + pattern: .*-apiservice$ + - it: has the correct image + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + apiServicePatchJob: + image: + repository: registry.k8s.io/ingress-nginx/kube-webhook-certgen + tag: "latest" + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: .*registry.k8s.io/ingress-nginx/kube-webhook-certgen:latest$ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_serviceaccount_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_serviceaccount_test.yaml new file mode 100644 index 000000000..9b6207c35 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/job_serviceaccount_test.yaml @@ -0,0 +1,79 @@ +suite: test job' serviceAccount +templates: + - templates/apiservice/job-patch/job-createSecret.yaml + - templates/apiservice/job-patch/job-patchAPIService.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: RBAC points to the service account that is created by default + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + rbac.create: true + serviceAccount.create: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: my-release-newrelic-k8s-metrics-adapter-apiservice + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + rbac.create: true + serviceAccount.create: false + serviceAccount.name: sa-test + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: sa-test + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + rbac.create: true + serviceAccount.create: false + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: default + + - it: has a linux node selector by default + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + + - it: has a linux node selector and additional selectors + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + nodeSelector: + aCoolTestLabel: aCoolTestValue + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + aCoolTestLabel: aCoolTestValue \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/rbac_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/rbac_test.yaml new file mode 100644 index 000000000..78884c022 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/tests/rbac_test.yaml @@ -0,0 +1,50 @@ +suite: test RBAC creation +templates: + - templates/apiservice/job-patch/rolebinding.yaml + - templates/apiservice/job-patch/clusterrolebinding.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: RBAC points to the service account that is created by default + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + rbac.create: true + serviceAccount.create: true + asserts: + - equal: + path: subjects[0].name + value: my-release-newrelic-k8s-metrics-adapter-apiservice + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + rbac.create: true + serviceAccount.create: false + serviceAccount.name: sa-test + asserts: + - equal: + path: subjects[0].name + value: sa-test + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + personalAPIKey: 21321 + cluster: test-cluster + config: + accountID: 111 + region: A-REGION + rbac.create: true + serviceAccount.create: false + asserts: + - equal: + path: subjects[0].name + value: default diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/values.yaml new file mode 100644 index 000000000..5c610f792 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-k8s-metrics-adapter/values.yaml @@ -0,0 +1,156 @@ +# IMPORTANT: The Kubernetes cluster name +# https://docs.newrelic.com/docs/kubernetes-monitoring-integration +# +# licenseKey: +# cluster: +# IMPORTANT: the previous values can also be set as global so that they +# can be shared by other newrelic product's charts. +# +# global: +# licenseKey: +# cluster: +# nrStaging: + +# -- New Relic [Personal API Key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#user-api-key) (stored in a secret). Used to connect to NerdGraph in order to fetch the configured metrics. (**Required**) +personalAPIKey: + +# -- Enable metrics adapter verbose logs. +verboseLog: false + +config: + # -- New Relic [Account ID](https://docs.newrelic.com/docs/accounts/accounts-billing/account-structure/account-id/) where the configured metrics are sourced from. (**Required**) + accountID: + + # config.region -- New Relic account region. If not set, it will be automatically derived from the License Key. + # @default -- Automatically detected from `licenseKey`. + region: + # For US-based accounts, the region is: `US`. + # For EU-based accounts, the region is: `EU`. + # For Staging accounts, the region is: 'Staging' this is also automatically derived form `global.nrStaging` + + + # config.cacheTTLSeconds -- Period of time in seconds in which a cached value of a metric is consider valid. + cacheTTLSeconds: 30 + # Not setting it or setting it to '0' disables the cache. + + # config.externalMetrics -- Contains all the external metrics definition of the adapter. Each key of the externalMetric entry represents the metric name and contains the parameters that defines it. + # @default -- See `values.yaml` + externalMetrics: + # Names cannot contain uppercase characters and + # "/" or "%" characters. + # my_external_metric_name_example: + # + # NRQL query that will executed to obtain the metric value. + # The query must return just one value so is recommended to use aggregator functions like average or latest. + # Default time span for aggregator func is 1h so is recommended to use the SINCE clause to reduce the time span. + # query: "FROM Metric SELECT average(`k8s.container.cpuCoresUtilization`) SINCE 2 MINUTES AGO" + # + # By default a cluster filter is added to the query to ensure no cross cluster metrics are taking into account. + # The added filter is equivalent to WHERE `clusterName`=. + # If metrics are not from the cluster use removeClusterFilter. Default value for this parameter is false. + # removeClusterFilter: false + + # config.nrdbClientTimeoutSeconds -- Defines the NRDB client timeout. The maximum allowed value is 120. + # @default -- 30 + nrdbClientTimeoutSeconds: 30 + +# image -- Registry, repository, tag, and pull policy for the container image. +# @default -- See `values.yaml`. +image: + registry: + repository: newrelic/newrelic-k8s-metrics-adapter + tag: "" + pullPolicy: IfNotPresent + # It is possible to specify docker registry credentials. + # See https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod + # image.pullSecrets -- The image pull secrets. + pullSecrets: [] + # - name: regsecret + +# -- Number of replicas in the deployment. +replicas: 1 + +# -- Resources you wish to assign to the pod. +# @default -- See `values.yaml` +resources: + limits: + memory: 80M + requests: + cpu: 100m + memory: 30M + +serviceAccount: + # -- Specifies whether a ServiceAccount should be created for the job and the deployment. + # false avoids creation, true or empty will create the ServiceAccount + # @default -- `true` + create: + # -- If `serviceAccount.create` this will be the name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template. + # If create is false, a serviceAccount with the given name must exist + # @default -- Automatically generated. + name: + +# -- Configure podSecurityContext +podSecurityContext: + +# -- Configure containerSecurityContext +containerSecurityContext: + +# -- Array to add extra environment variables +extraEnv: [] +# -- Array to add extra envFrom +extraEnvFrom: [] +# -- Array to add extra volumes +extraVolumes: [] +# -- Add extra volume mounts +extraVolumeMounts: [] + +# -- Additional annotations to apply to the pod(s). +podAnnotations: + +# Due to security restrictions, some users might require to use a https proxy to route traffic over the internet. +# In this specific case, when the metrics adapter sends a request to the New Relic backend. If this is the case +# for you, set this value to your http proxy endpoint. +# -- Configure proxy for the metrics-adapter. +proxy: + +# Pod scheduling priority +# Ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +# priorityClassName: high-priority + +# fullnameOverride -- To fully override common.naming.fullname +fullnameOverride: "" +# -- Node affinity to use for scheduling. +affinity: {} +# -- Node label to use for scheduling. +nodeSelector: {} +# -- List of node taints to tolerate (requires Kubernetes >= 1.6) +tolerations: [] + +apiServicePatchJob: + # apiServicePatchJob.image -- Registry, repository, tag, and pull policy for the job container image. + # @default -- See `values.yaml`. + image: + registry: # defaults to registry.k8s.io + repository: ingress-nginx/kube-webhook-certgen + tag: v1.3.0 + pullPolicy: IfNotPresent + + # -- Additional Volumes for Cert Job. + volumes: [] + # - name: tmp + # emptyDir: {} + + # -- Additional Volume mounts for Cert Job, you might want to mount tmp if Pod Security Policies. + volumeMounts: [] + # - name: tmp + # mountPath: /tmp + # Enforce a read-only root. + +certManager: + # -- Use cert manager for APIService certs, rather than the built-in patch job. + enabled: false + +rbac: + # rbac.pspEnabled -- Whether the chart should create Pod Security Policy objects. + pspEnabled: false diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/Chart.lock new file mode 100644 index 000000000..064abf8aa --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +digest: sha256:fa87cb007564a39a72739a3e850a91d6b03c0fc27a1115deac042b3ef77b4142 +generated: "2024-07-17T19:29:15.951407+05:30" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/Chart.yaml new file mode 100644 index 000000000..d96fc32c8 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/Chart.yaml @@ -0,0 +1,20 @@ +apiVersion: v2 +appVersion: 2.0.0 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +description: A Helm chart to deploy New Relic Kubernetes Logging as a DaemonSet, supporting + both Linux and Windows nodes and containers +home: https://github.com/newrelic/kubernetes-logging +icon: https://newrelic.com/assets/newrelic/source/NewRelic-logo-square.svg +keywords: +- logging +- newrelic +maintainers: +- email: logging-team@newrelic.com + name: jsubirat +- name: danybmx +- name: sdaubin +name: newrelic-logging +version: 1.22.3 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/README.md new file mode 100644 index 000000000..2f7e4e853 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/README.md @@ -0,0 +1,267 @@ +# newrelic-logging + + +## Chart Details +New Relic offers a [Fluent Bit](https://fluentbit.io/) output [plugin](https://github.com/newrelic/newrelic-fluent-bit-output) to easily forward your logs to [New Relic Logs](https://docs.newrelic.com/docs/logs/new-relic-logs/get-started/introduction-new-relic-logs). This plugin is also provided in a standalone Docker image that can be installed in a [Kubernetes](https://kubernetes.io/) cluster in the form of a [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/), which we refer as the Kubernetes plugin. + +This document explains how to install it in your cluster using our [Helm](https://helm.sh/) chart. + + +## Install / Upgrade / Uninstall instructions +Despite the `newrelic-logging` chart being able to work standalone, we recommend installing it as part of the [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) chart. The best way of doing so is through the guided installation process documented [here](https://docs.newrelic.com//docs/kubernetes-pixie/kubernetes-integration/installation/kubernetes-integration-install-configure/). This guided install can generate the Helm 3 commands required to install it (select "Helm 3" in Step 3 from the previous documentation link). You can also opt to install it manually using Helm by following [these steps](https://docs.newrelic.com//docs/kubernetes-pixie/kubernetes-integration/installation/install-kubernetes-integration-using-helm/#install-k8-helm). To uninstall it, refer to the steps outlined in [this page](https://docs.newrelic.com/docs/kubernetes-pixie/kubernetes-integration/uninstall-kubernetes/). + +### Installing or updating the helm New Relic repository + +To install the repo you can run: +``` +helm repo add newrelic https://helm-charts.newrelic.com +``` + +To update the repo you can run: +``` +helm repo update newrelic +``` + +## Configuration + +### How to configure the chart +The `newrelic-logging` chart can be installed either alone or as part of the [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) chart (recommended). The chart default settings should be suitable for most users. Nevertheless, you may be interested in overriding the defaults, either by passing them through a `values-newrelic.yaml` file or via the command line when installing the chart. Depending on how you installed it, you'll need to specify the `newrelic-logging`-specific configuration values using the chart name (`newrelic-logging`) as a prefix. In the table below, you can find a quick reference of how to configure the chart in these scenarios. The example depicts how you'd specify the mandatory `licenseKey` and `cluster` settings and how you'd override the `fluentBit.retryLimit` setting to `10`. + + + + + + + + + + + + + + + + + +
Installation methodConfiguration via values.yamlConfiguration via command line
Standalone newrelic-logging + + +``` +# values-newrelic.yaml configuration contents + +licenseKey: _YOUR_NEW_RELIC_LICENSE_KEY_ +cluster: _K8S_CLUSTER_NAME_ + +fluentBit: + retryLimit: 10 +``` + +``` +# Install / upgrade command + +helm upgrade --install newrelic-logging newrelic/newrelic-logging \ +--namespace newrelic \ +--create-namespace \ +-f values-newrelic.yaml +``` + + +``` +# Install / upgrade command + +helm upgrade --install newrelic-logging newrelic/newrelic-logging \ +--namespace=newrelic \ +--set licenseKey=_YOUR_NEW_RELIC_LICENSE_KEY_ \ +--set cluster=_K8S_CLUSTER_NAME_ \ +--set fluentBit.retryLimit=10 +``` +
As part of nri-bundle + +``` +# values-newrelic.yaml configuration contents + +# General settings that apply to all the child charts +global: + licenseKey: _YOUR_NEW_RELIC_LICENSE_KEY_ + cluster: _K8S_CLUSTER_NAME_ + +# Specific configuration for the newrelic-logging child chart +newrelic-logging: + fluentBit: + retryLimit: 10 +``` + +``` +# Install / upgrade command + +helm upgrade --install newrelic-bundle newrelic/nri-bundle \ + --namespace newrelic \ + --create-namespace \ + -f values-newrelic.yaml \ +``` + + +``` +# Install / upgrade command + +helm upgrade --install newrelic-bundle newrelic/nri-bundle \ +--namespace=newrelic \ +--set global.licenseKey=_YOUR_NEW_RELIC_LICENSE_KEY_ \ +--set global.cluster=_K8S_CLUSTER_NAME_ \ +--set newrelic-logging.fluentBit.retryLimit=10 +``` +
+ + +### Supported configuration parameters +See [values.yaml](values.yaml) for the default values + +| Parameter | Description | Default | +|--------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------| +| `global.cluster` - `cluster` | The cluster name for the Kubernetes cluster. | | +| `global.licenseKey` - `licenseKey` | The [license key](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/license-key) for your New Relic Account. This will be the preferred configuration option if both `licenseKey` and `customSecret*` values are specified. | | +| `global.customSecretName` - `customSecretName` | Name of the Secret object where the license key is stored | | +| `global.customSecretLicenseKey` - `customSecretLicenseKey` | Key in the Secret object where the license key is stored. | | +| `global.fargate` | Must be set to `true` when deploying in an EKS Fargate environment. Prevents DaemonSet pods from being scheduled in Fargate nodes. | | +| `global.lowDataMode` - `lowDataMode` | If `true`, send minimal attributes on Kubernetes logs. Labels and annotations are not sent when lowDataMode is enabled. | `false` | +| `rbac.create` | Enable Role-based authentication | `true` | +| `rbac.pspEnabled` | Enable pod security policy support | `false` | +| `image.repository` | The container to pull. | `newrelic/newrelic-fluentbit-output` | +| `image.pullPolicy` | The pull policy. | `IfNotPresent` | +| `image.pullSecrets` | Image pull secrets. | `nil` | +| `image.tag` | The version of the container to pull. | See value in [values.yaml]` | +| `exposedPorts` | Any ports you wish to expose from the pod. Ex. 2020 for metrics | `[]` | +| `resources` | Any resources you wish to assign to the pod. | See Resources below | +| `priorityClassName` | Scheduling priority of the pod | `nil` | +| `nodeSelector` | Node label to use for scheduling on Linux nodes | `{ kubernetes.io/os: linux }` | +| `windowsNodeSelector` | Node label to use for scheduling on Windows nodes | `{ kubernetes.io/os: windows, node.kubernetes.io/windows-build: BUILD_NUMBER }` | +| `tolerations` | List of node taints to tolerate (requires Kubernetes >= 1.6) | See Tolerations below | +| `updateStrategy` | Strategy for DaemonSet updates (requires Kubernetes >= 1.6) | `RollingUpdate` | +| `extraVolumeMounts` | Additional DaemonSet volume mounts | `[]` | +| `extraVolumes` | Additional DaemonSet volumes | `[]` | +| `initContainers` | [Init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) that will be executed before the actual container in charge of shipping logs to New Relic is initialized. Use this if you are using a custom Fluent Bit configuration that requires downloading certain files inside the volumes being accessed by the log-shipping pod. | `[]` | +| `windows.initContainers` | [Init containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) that will be executed before the actual container in charge of shipping logs to New Relic is initialized. Use this if you are using a custom Fluent Bit configuration that requires downloading certain files inside the volumes being accessed by the log-shipping pod. | `[]` | +| `serviceAccount.create` | If true, a service account would be created and assigned to the deployment | `true` | +| `serviceAccount.name` | The service account to assign to the deployment. If `serviceAccount.create` is true then this name will be used when creating the service account | | +| `serviceAccount.annotations` | The annotations to add to the service account if `serviceAccount.create` is set to true. | | +| `global.nrStaging` - `nrStaging` | Send data to staging (requires a staging license key) | `false` | +| `fluentBit.path` | Node path logs are forwarded from. Patterns are supported, as well as specifying multiple paths/patterns separated by commas. | `/var/log/containers/*.log` | +| `fluentBit.linuxMountPath` | The path mounted on linux Fluent-Bit pods to read logs from. Defaults to /var because some engines write the logs to /var/log and others to /var/lib (symlinked to /var/log) so Fluent-Bit need access to both in those cases | `/var` | +| `fluentBit.db` | Node path used by Fluent Bit to store a database file to keep track of monitored files and offsets. | `/var/log/containers/*.log` | +| `fluentBit.k8sBufferSize` | Set the buffer size for HTTP client when reading responses from Kubernetes API server. A value of 0 results in no limit and the buffer will expand as needed. | `32k` | +| `fluentBit.k8sLoggingExclude` | Set to "true" to allow excluding pods by adding the annotation `fluentbit.io/exclude: "true"` to pods you wish to exclude. | `false` | +| `fluentBit.additionalEnvVariables` | Additional environmental variables for fluentbit pods | `[]]` | +| `fluentBit.persistence.mode` | The [persistence mode](#Fluent-Bit-persistence-modes) you want to use, options are "hostPath", "none" or "persistentVolume" (this last one available only for linux) | +| `fluentBit.persistence.persistentVolume.storageClass` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), indicates the storage class that will be used for create the PersistentVolume and PersistentVolumeClaim. | | +| `fluentBit.persistence.persistentVolume.size` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), indicates the capacity for the PersistentVolume and PersistentVolumeClaim | 10Gi | +| `fluentBit.persistence.persistentVolume.dynamicProvisioning` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), indicates if the storage class used provide dynamic provisioning. If it does, only the PersistentVolumeClaim will be created. | true | +| `fluentBit.persistence.persistentVolume.existingVolume` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), indicates and existing volume in case you want to reuse one, bear in mind that it should allow ReadWriteMany access mode. A PersistentVolumeClaim will be created using it. | | +| `fluentBit.persistence.persistentVolume.existingVolumeClaim` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), indicates and existing volume claim that will be used on the daemonset. It should allow ReadWriteMany access mode. | | +| `fluentBit.persistence.persistentVolume.annotations.volume` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), allows to add annotations to the PersistentVolume (if created). | | +| `fluentBit.persistence.persistentVolume.annotations.claim` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), allows to add annotations to the PersistentVolumeClaim (if created). | | +| `fluentBit.persistence.persistentVolume.extra.volume` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), allows to add extra properties to the PersistentVolume (if created). | | +| `fluentBit.persistence.persistentVolume.extra.claim` | On "persistentVolume" [persistence mode](#Fluent-Bit-persistence-modes), allows to add extra properties to the PersistentVolumeClaim (if created). | | +| `daemonSet.annotations` | The annotations to add to the `DaemonSet`. | | +| `podAnnotations` | The annotations to add to the `DaemonSet` created `Pod`s. | | +| `enableLinux` | Enable log collection from Linux containers. This is the default behavior. In case you are only interested of collecting logs from Windows containers, set this to `false`. | `true` | +| `enableWindows` | Enable log collection from Windows containers. Please refer to the [Windows support](#windows-support) section for more details. | `false` | +| `fluentBit.config.service` | Contains fluent-bit.conf Service config | | +| `fluentBit.config.inputs` | Contains fluent-bit.conf Inputs config | | +| `fluentBit.config.extraInputs` | Contains extra fluent-bit.conf Inputs config | | +| `fluentBit.config.filters` | Contains fluent-bit.conf Filters config | | +| `fluentBit.config.extraFilters` | Contains extra fluent-bit.conf Filters config | | +| `fluentBit.config.lowDataModeFilters` | Contains fluent-bit.conf Filters config for lowDataMode | | +| `fluentBit.config.outputs` | Contains fluent-bit.conf Outputs config | | +| `fluentBit.config.extraOutputs` | Contains extra fluent-bit.conf Outputs config | | +| `fluentBit.config.parsers` | Contains parsers.conf Parsers config | | +| `fluentBit.retryLimit` | Amount of times to retry sending a given batch of logs to New Relic. This prevents data loss if there is a temporary network disruption, if a request to the Logs API is lost or when receiving a recoverable HTTP response. Set it to "False" for unlimited retries. | 5 | +| `fluentBit.sendMetrics` | Enable the collection of Fluent Bit internal metrics in Prometheus format as well as newrelic-fluent-bit-output internal plugin metrics. See [this documentation page](https://docs.newrelic.com/docs/logs/forward-logs/kubernetes-plugin-log-forwarding/#troubleshoot-installation) for more details. | `false` | +| `dnsConfig` | [DNS configuration](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-dns-config) that will be added to the pods. Can be configured also with `global.dnsConfig`. | `{}` | +| `fluentBit.criEnabled` | We assume that `kubelet`directly communicates with the container engine using the [CRI](https://kubernetes.io/docs/concepts/overview/components/#container-runtime) specification. Set this to `false` if your K8s installation uses [dockershim](https://kubernetes.io/docs/tasks/administer-cluster/migrating-from-dockershim/) instead, in order to get the logs properly parsed. | `true` | + +### Fluent Bit persistence modes + +Fluent Bit uses a database file to keep track of log lines read from files (offsets). This database file is stored in the host node by default, using a `hostPath` mount. It's specifically stored (by default) in `/var/log/flb_kube.db` to keep things simple, as we're already mounting `/var` for accessing container logs. + +Sometimes the security constraints of some clusters don't allow mounting `hostPath`s in read-write mode. That's why you can chose among the following +persistence modes. Each one has their pros and cons. + +- `hostPath` (default) will use a `hostPath` mount to store the DB file on the node disk. This is the easiest, cheapest an most reliable option, but prohibited by some cloud vendor security policies. +- `none` will disable the Fluent Bit DB file. This can cause log duplication or data loss in case Fluent Bit gets restarted. +- `persistentVolume` (Linux only) will use a `ReadWriteMany` persistent volume to store the DB file. This will override the `fluentBit.db` path and use `/db/${NODE_NAME}-fb.db` instead. If you use this option in a Windows cluster it will default to `none` on Windows nodes. + +#### GKE Autopilot example + +If you're using the `persistentVolume` persistence mode you need to provide at least the `storageClass`, and it should be `ReadWriteMany`. This is an example of the configuration for persistence in [GKE Autopilot](https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-overview). + +``` +fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: standard-rwx + linuxMountPath: /var/log +``` + +### Proxy support + +Since Fluent Bit Kubernetes plugin is using [newrelic-fluent-bit-output](https://github.com/newrelic/newrelic-fluent-bit-output) we can configure the [proxy support](https://github.com/newrelic/newrelic-fluent-bit-output#proxy-support) in order to set up the proxy configuration. + +#### As environment variables + +The easiest way to configure the proxy is by means of specifying the `HTTP_PROXY` or `HTTPS_PROXY` variables as follows: + +``` +# values-newrelic.yml + +fluentBit: + additionalEnvVariables: + - name: HTTPS_PROXY + value: https://your-https-proxy-hostname:3129 +``` + + +#### Custom proxy configuration (for proxies using self-signed certificates) + +If you need to use a proxy using self-signed certificates, you'll need to mount a volume with the Certificate Authority +bundle file and reference it from the Fluent Bit configuration as follows: + +``` +# values-newrelic.yaml +extraVolumes: [] + - name: proxyConfig + # Example using hostPath. You can also place the caBundleFile.pem contents in a ConfigMap and reference it here instead, + # as explained here: https://kubernetes.io/docs/concepts/storage/volumes/#configmap + hostPath: + path: /path/in/node/to/your/caBundleFile.pem + +extraVolumeMounts: [] + - name: proxyConfig + mountPath: /proxyConfig/caBundleFile.pem + +fluentBit: + config: + outputs: | + [OUTPUT] + Name newrelic + Match * + licenseKey ${LICENSE_KEY} + endpoint ${ENDPOINT} + lowDataMode ${LOW_DATA_MODE} + Retry_Limit ${RETRY_LIMIT} + proxy https://your-https-proxy-hostname:3129 + caBundleFile /proxyConfig/caBundleFile.pem +``` + + +## Windows support + +Since version `1.7.0`, this Helm chart supports shipping logs from Windows containers. To this end, you need to set the `enableWindows` configuration parameter to `true`. + +Windows containers have some constraints regarding Linux containers. The main one being that they can only be executed on _hosts_ using the exact same Windows version and build number. On the other hand, Kubernetes nodes only supports the Windows versions listed [here](https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/#windows-os-version-support). + +This Helm chart deploys one `DaemonSet` for each of the Windows versions it supports, while ensuring that only containers matching the host operating system will be deployed in each host. + +This Helm chart currently supports the following Windows versions: +- Windows Server LTSC 2019, build 10.0.17763 +- Windows Server LTSC 2022, build 10.0.20348 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/Chart.yaml new file mode 100644 index 000000000..b65ac15d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +- name: kang-makes + url: https://github.com/kang-makes +name: common-library +type: library +version: 1.2.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/DEVELOPERS.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/DEVELOPERS.md new file mode 100644 index 000000000..3ccc108e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/DEVELOPERS.md @@ -0,0 +1,663 @@ +# Functions/templates documented for chart writers +Here is some rough documentation separated by the file that contains the function, the function +name and how to use it. We are not covering functions that start with `_` (e.g. +`newrelic.common.license._licenseKey`) because they are used internally by this library for +other helpers. Helm does not have the concept of "public" or "private" functions/templates so +this is a convention of ours. + +## _naming.tpl +These functions are used to name objects. + +### `newrelic.common.naming.name` +This is the same as the idiomatic `CHART-NAME.name` that is created when you use `helm create`. + +It honors `.Values.nameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.name" . }} +``` + +### `newrelic.common.naming.fullname` +This is the same as the idiomatic `CHART-NAME.fullname` that is created when you use `helm create` + +It honors `.Values.fullnameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.fullname" . }} +``` + +### `newrelic.common.naming.chart` +This is the same as the idiomatic `CHART-NAME.chart` that is created when you use `helm create`. + +It is mostly useless for chart writers. It is used internally for templating the labels but there +is no reason to keep it "private". + +Usage: +```mustache +{{ include "newrelic.common.naming.chart" . }} +``` + +### `newrelic.common.naming.truncateToDNS` +This is a useful template that could be used to trim a string to 63 chars and does not end with a dash (`-`). +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $truncatedName := include "newrelic.common.naming.truncateToDNS" $nameToTruncate }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-string-that-should-be */ -}} +``` + +### `newrelic.common.naming.truncateToDNSWithSuffix` +This template function is the same as the above but instead of receiving a string you should give a `dict` +with a `name` and a `suffix`. This function will join them with a dash (`-`) and trim the `name` so the +result of `name-suffix` is no more than 63 chars + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $suffix := "A-NOT-SO-LONG-SUFFIX" }} +{{- $truncatedName := include "truncateToDNSWithSuffix" (dict "name" $nameToTruncate "suffix" $suffix) }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-A-NOT-SO-LONG-SUFFIX */ -}} +``` + + + +## _labels.tpl +### `newrelic.common.labels`, `newrelic.common.labels.selectorLabels` and `newrelic.common.labels.podLabels` +These are functions that are used to label objects. They are configured by this `values.yaml` +```yaml +global: + podLabels: {} # included in all the pods of all the charts that implement this library + labels: {} # included in all the objects of all the charts that implement this library +podLabels: {} # included in all the pods of this chart +labels: {} # included in all the objects of this chart +``` + +label maps are merged from global to local values. + +And chart writer should use them like this: +```mustache +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} +``` + +`newrelic.common.labels.podLabels` includes `newrelic.common.labels.selectorLabels` automatically. + + + +## _priority-class-name.tpl +### `newrelic.common.priorityClassName` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + priorityClassName: "" +priorityClassName: "" +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `priorityClassName` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} +``` + + + +## _hostnetwork.tpl +### `newrelic.common.hostNetwork` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + hostNetwork: # Note that this is empty (nil) +hostNetwork: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `hostNetwork` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.hostNetwork" . }} + hostNetwork: {{ . }} + {{- end }} +``` + +### `newrelic.common.hostNetwork.value` +This function is an abstraction of the function above but this returns directly "true" or "false". + +Be careful with using this with an `if` as Helm does evaluate "false" (string) as `true`. + +Usage (example in a pod spec): +```mustache +spec: + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} +``` + + + +## _dnsconfig.tpl +### `newrelic.common.dnsConfig` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + dnsConfig: {} +dnsConfig: {} +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `dnsConfig` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _images.tpl +These functions help us to deal with how images are templated. This allows setting `registries` +where to fetch images globally while being flexible enough to fit in different maps of images +and deployments with one or more images. This is the example of a complex `values.yaml` that +we are going to use during the documentation of these functions: + +```yaml +global: + images: + registry: nexus-3-instance.internal.clients-domain.tld +jobImage: + registry: # defaults to "example.tld" when empty in these examples + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent + pullSecrets: [] +images: + integration: + registry: + repository: newrelic/nri-kube-events + tag: 1.8.0 + pullPolicy: IfNotPresent + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.22.0 + pullPolicy: IfNotPresent + pullSecrets: [] +``` + +### `newrelic.common.images.image` +This will return a string with the image ready to be downloaded that includes the registry, the image and the tag. +`defaultRegistry` is used to keep `registry` field empty in `values.yaml` so you can override the image using +`global.images.registry`, your local `jobImage.registry` and be able to fallback to a registry that is not `docker.io` +(Or the default repository that the client could have set in the CRI). + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.image" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.registry` +It returns the registry from the global or local values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.registry" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.repository` +It returns the image from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.tag` +It returns the image's tag from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.renderPullSecrets` +If returns a merged map that contains the pull secrets from the global configuration and the local one. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.jobImage.pullSecrets "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +``` + + + +## _serviceaccount.tpl +These functions are used to evaluate if the service account should be created, with which name and add annotations to it. + +The functions that the common library has implemented for service accounts are: +* `newrelic.common.serviceAccount.create` +* `newrelic.common.serviceAccount.name` +* `newrelic.common.serviceAccount.annotations` + +Usage: +```mustache +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +``` + + + +## _affinity.tpl, _nodeselector.tpl and _tolerations.tpl +These three files are almost the same and they follow the idiomatic way of `helm create`. + +Each function also looks if there is a global value like the other helpers. +```yaml +global: + affinity: {} + nodeSelector: {} + tolerations: [] +affinity: {} +nodeSelector: {} +tolerations: [] +``` + +The values here are replaced instead of be merged. If a value at root level is found, the global one is ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _agent-config.tpl +### `newrelic.common.agentConfig.defaults` +This returns a YAML that the agent can use directly as a config that includes other options from the values file like verbose mode, +custom attributes, FedRAMP and such. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include newrelic.common.naming.truncateToDNSWithSuffix (dict "name" (include "newrelic.common.naming.fullname" .) suffix "agent-config") }} + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "newrelic.common.agentConfig.defaults" . | nindent 4 }} +``` + + + +## _cluster.tpl +### `newrelic.common.cluster` +Returns the cluster name + +Usage: +```mustache +{{ include "newrelic.common.cluster" . }} +``` + + + +## _custom-attributes.tpl +### `newrelic.common.customAttributes` +Return custom attributes in YAML format. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + name: example +data: + custom-attributes.yaml: | + {{- include "newrelic.common.customAttributes" . | nindent 4 }} + custom-attributes.json: | + {{- include "newrelic.common.customAttributes" . | fromYaml | toJson | nindent 4 }} +``` + + + +## _fedramp.tpl +### `newrelic.common.fedramp.enabled` +Returns true if FedRAMP is enabled or an empty string if not. It can be safely used in conditionals as an empty string is a Helm falsiness. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled" . }} +``` + +### `newrelic.common.fedramp.enabled.value` +Returns true if FedRAMP is enabled or false if not. This is to have the value of FedRAMP ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled.value" . }} +``` + + + +## _license.tpl +### `newrelic.common.license.secretName` and ### `newrelic.common.license.secretKeyName` +Returns the secret and key inside the secret where to read the license key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the license key. + +To create the secret use `newrelic.common.license.secret`. + +Usage: +```mustache +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + containers: + - name: agent + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} +``` + + + +## _license_secret.tpl +### `newrelic.common.license.secret` +This function templates the secret that is used by agents and integrations with the license Key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any license key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.license.secret" . -}} +``` + + + +## _insights.tpl +### `newrelic.common.insightsKey.secretName` and ### `newrelic.common.insightsKey.secretKeyName` +Returns the secret and key inside the secret where to read the insights key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the insights key. + +To create the secret use `newrelic.common.insightsKey.secret`. + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: statsd +spec: + containers: + - name: statsd + env: + - name: "INSIGHTS_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + key: {{ include "newrelic.common.insightsKey.secretKeyName" . }} +``` + + + +## _insights_secret.tpl +### `newrelic.common.insightsKey.secret` +This function templates the secret that is used by agents and integrations with the insights key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any insights key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.insightsKey.secret" . -}} +``` + + + +## _low-data-mode.tpl +### `newrelic.common.lowDataMode` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + lowDataMode: # Note that this is empty (nil) +lowDataMode: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `lowdataMode` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.lowDataMode" . }} +``` + + + +## _privileged.tpl +### `newrelic.common.privileged` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + privileged: # Note that this is empty (nil) +privileged: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `privileged` is defined, the global one is going to be always ignored. + +Chart writers could override this and put directly a `true` in the `values.yaml` to override the +default of the common library. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.privileged" . }} +``` + +### `newrelic.common.privileged.value` +Returns true if privileged mode is enabled or false if not. This is to have the value of privileged ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.privileged.value" . }} +``` + + + +## _proxy.tpl +### `newrelic.common.proxy` +Returns the proxy URL configured by the user. + +Usage: +```mustache +{{ include "newrelic.common.proxy" . }} +``` + + + +## _security-context.tpl +Use these functions to share the security context among all charts. Useful in clusters that have security enforcing not to +use the root user (like OpenShift) or users that have an admission webhooks. + +The functions are: +* `newrelic.common.securityContext.container` +* `newrelic.common.securityContext.pod` + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + spec: + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + containers: + - name: example + {{- with include "nriKubernetes.securityContext.container" . }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} +``` + + + +## _staging.tpl +### `newrelic.common.nrStaging` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + nrStaging: # Note that this is empty (nil) +nrStaging: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `nrStaging` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging" . }} +``` + +### `newrelic.common.nrStaging.value` +Returns true if staging is enabled or false if not. This is to have the staging value ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging.value" . }} +``` + + + +## _verbose-log.tpl +### `newrelic.common.verboseLog` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + verboseLog: # Note that this is empty (nil) +verboseLog: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `verboseLog` is defined, the global one is going to be always ignored. + +Usage: +```mustache +{{ include "newrelic.common.verboseLog" . }} +``` + +### `newrelic.common.verboseLog.valueAsBoolean` +Returns true if verbose is enabled or false if not. This is to have the verbose value ready to be templated as a boolean + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsBoolean" . }} +``` + +### `newrelic.common.verboseLog.valueAsInt` +Returns 1 if verbose is enabled or 0 if not. This is to have the verbose value ready to be templated as an integer + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsInt" . }} +``` diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/README.md new file mode 100644 index 000000000..10f08ca67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/README.md @@ -0,0 +1,106 @@ +# Helm Common library + +The common library is a way to unify the UX through all the Helm charts that implement it. + +The tooling suite that New Relic is huge and growing and this allows to set things globally +and locally for a single chart. + +## Documentation for chart writers + +If you are writing a chart that is going to use this library you can check the [developers guide](/library/common-library/DEVELOPERS.md) to see all +the functions/templates that we have implemented, what they do and how to use them. + +## Values managed globally + +We want to have a seamless experience through all the charts so we created this library that tries to standardize the behaviour +of all the charts. Sadly, because of the complexity of all these integrations, not all the charts behave exactly as expected. + +An example is `newrelic-infrastructure` that ignores `hostNetwork` in the control plane scraper because most of the users has the +control plane listening in the node to `localhost`. + +For each chart that has a special behavior (or further information of the behavior) there is a "chart particularities" section +in its README.md that explains which is the expected behavior. + +At the time of writing this, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this +library and honors global options as described in this document. + +Here is a list of global options: + +| Global keys | Local keys | Default | Merged[1](#values-managed-globally-1) | Description | +|-------------|------------|---------|--------------------------------------------------|-------------| +| global.cluster | cluster | `""` | | Name of the Kubernetes cluster monitored | +| global.licenseKey | licenseKey | `""` | | This set this license key to use | +| global.customSecretName | customSecretName | `""` | | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there | +| global.customSecretLicenseKey | customSecretLicenseKey | `""` | | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located | +| global.podLabels | podLabels | `{}` | yes | Additional labels for chart pods | +| global.labels | labels | `{}` | yes | Additional labels for chart objects | +| global.priorityClassName | priorityClassName | `""` | | Sets pod's priorityClassName | +| global.hostNetwork | hostNetwork | `false` | | Sets pod's hostNetwork | +| global.dnsConfig | dnsConfig | `{}` | | Sets pod's dnsConfig | +| global.images.registry | See [Further information](#values-managed-globally-2) | `""` | | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.images.pullSecrets | See [Further information](#values-managed-globally-2) | `[]` | yes | Set secrets to be able to fetch images | +| global.podSecurityContext | podSecurityContext | `{}` | | Sets security context (at pod level) | +| global.containerSecurityContext | containerSecurityContext | `{}` | | Sets security context (at container level) | +| global.affinity | affinity | `{}` | | Sets pod/node affinities | +| global.nodeSelector | nodeSelector | `{}` | | Sets pod's node selector | +| global.tolerations | tolerations | `[]` | | Sets pod's tolerations to node taints | +| global.serviceAccount.create | serviceAccount.create | `true` | | Configures if the service account should be created or not | +| global.serviceAccount.name | serviceAccount.name | name of the release | | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. | +| global.serviceAccount.annotations | serviceAccount.annotations | `{}` | yes | Add these annotations to the service account we create | +| global.customAttributes | customAttributes | `{}` | | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.fedramp | fedramp | `false` | | Enables FedRAMP | +| global.lowDataMode | lowDataMode | `false` | | Reduces number of metrics sent in order to reduce costs | +| global.privileged | privileged | Depends on the chart | | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | +| global.proxy | proxy | `""` | | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.nrStaging | nrStaging | `false` | | Send the metrics to the staging backend. Requires a valid staging license key | +| global.verboseLog | verboseLog | `false` | | Sets the debug/trace logs to this integration or all integrations if it is set globally | + +### Further information + +#### 1. Merged + +Merged means that the values from global are not replaced by the local ones. Think in this example: +```yaml +global: + labels: + global: global + hostNetwork: true + nodeSelector: + global: global + +labels: + local: local +nodeSelector: + local: local +hostNetwork: false +``` + +This values will template `hostNetwork` to `false`, a map of labels `{ "global": "global", "local": "local" }` and a `nodeSelector` with +`{ "local": "local" }`. + +As Helm by default merges all the maps it could be confusing that we have two behaviors (merging `labels` and replacing `nodeSelector`) +the `values` from global to local. This is the rationale behind this: +* `hostNetwork` is templated to `false` because is overriding the value defined globally. +* `labels` are merged because the user may want to label all the New Relic pods at once and label other solution pods differently for + clarity' sake. +* `nodeSelector` does not merge as `labels` because could make it harder to overwrite/delete a selector that comes from global because + of the logic that Helm follows merging maps. + + +#### 2. Fine grain registries + +Some charts only have 1 image while others that can have 2 or more images. The local path for the registry can change depending +on the chart itself. + +As this is mostly unique per helm chart, you should take a look to the chart's values table (or directly to the `values.yaml` file to see all the +images that you can change. + +This should only be needed if you have an advanced setup that forces you to have granularity enough to force a proxy/cache registry per integration. + + + +#### 3. Privileged mode + +By default, from the common library, the privileged mode is set to false. But most of the helm charts require this to be true to fetch more +metrics so could see a true in some charts. The consequences of the privileged mode differ from one chart to another so for each chart that +honors the privileged mode toggle should be a section in the README explaining which is the behavior with it enabled or disabled. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_affinity.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_affinity.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod affinity */ -}} +{{- define "newrelic.common.affinity" -}} + {{- if .Values.affinity -}} + {{- toYaml .Values.affinity -}} + {{- else if .Values.global -}} + {{- if .Values.global.affinity -}} + {{- toYaml .Values.global.affinity -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_agent-config.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..9c32861a0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,26 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +log: + level: trace +{{- end }} + +{{- if (include "newrelic.common.nrStaging" . ) }} +staging: true +{{- end }} + +{{- with include "newrelic.common.proxy" . }} +proxy: {{ . | quote }} +{{- end }} + +{{- with include "newrelic.common.fedramp.enabled" . }} +fedramp: {{ . }} +{{- end }} + +{{- with fromYaml ( include "newrelic.common.customAttributes" . ) }} +custom_attributes: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_cluster.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_cluster.tpl @@ -0,0 +1,15 @@ +{{/* +Return the cluster +*/}} +{{- define "newrelic.common.cluster" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.cluster -}} + {{- .Values.cluster -}} +{{- else if $global.cluster -}} + {{- $global.cluster -}} +{{- else -}} + {{ fail "There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required." }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_custom-attributes.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_custom-attributes.tpl @@ -0,0 +1,17 @@ +{{/* +This will render custom attributes as a YAML ready to be templated or be used with `fromYaml`. +*/}} +{{- define "newrelic.common.customAttributes" -}} +{{- $customAttributes := dict -}} + +{{- $global := index .Values "global" | default dict -}} +{{- if $global.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes $global.customAttributes -}} +{{- end -}} + +{{- if .Values.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes .Values.customAttributes -}} +{{- end -}} + +{{- toYaml $customAttributes -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_dnsconfig.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_dnsconfig.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod dnsConfig */ -}} +{{- define "newrelic.common.dnsConfig" -}} + {{- if .Values.dnsConfig -}} + {{- toYaml .Values.dnsConfig -}} + {{- else if .Values.global -}} + {{- if .Values.global.dnsConfig -}} + {{- toYaml .Values.global.dnsConfig -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_fedramp.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_fedramp.tpl @@ -0,0 +1,25 @@ +{{- /* Defines the fedRAMP flag */ -}} +{{- define "newrelic.common.fedramp.enabled" -}} + {{- if .Values.fedramp -}} + {{- if .Values.fedramp.enabled -}} + {{- .Values.fedramp.enabled -}} + {{- end -}} + {{- else if .Values.global -}} + {{- if .Values.global.fedramp -}} + {{- if .Values.global.fedramp.enabled -}} + {{- .Values.global.fedramp.enabled -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{- /* Return FedRAMP value directly ready to be templated */ -}} +{{- define "newrelic.common.fedramp.enabled.value" -}} +{{- if include "newrelic.common.fedramp.enabled" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_hostnetwork.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_hostnetwork.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the hostNetwork toggle. +This helper allows to override the global `.global.hostNetwork` with the value of `.hostNetwork`. +Returns "true" if `hostNetwork` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.hostNetwork" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- /* +`get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs + +We also want only to return when this is true, returning `false` here will template "false" (string) when doing +an `(include "newrelic.common.hostNetwork" .)`, which is not an "empty string" so it is `true` if it is used +as an evaluation somewhere else. +*/ -}} +{{- if get .Values "hostNetwork" | kindIs "bool" -}} + {{- if .Values.hostNetwork -}} + {{- .Values.hostNetwork -}} + {{- end -}} +{{- else if get $global "hostNetwork" | kindIs "bool" -}} + {{- if $global.hostNetwork -}} + {{- $global.hostNetwork -}} + {{- end -}} +{{- end -}} +{{- end -}} + + +{{- /* +Abstraction of the hostNetwork toggle. +This helper abstracts the function "newrelic.common.hostNetwork" to return true or false directly. +*/ -}} +{{- define "newrelic.common.hostNetwork.value" -}} +{{- if include "newrelic.common.hostNetwork" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_images.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..d4fb43290 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_images.tpl @@ -0,0 +1,94 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "defaultRegistry" .defaultRegistry "context" .context ) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic.common.images.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image registry +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} +{{- $globalRegistry := "" -}} +{{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- with .context.Values.global.images.registry -}} + {{- $globalRegistry = . -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- $localRegistry := "" -}} +{{- if .imageRoot.registry -}} + {{- $localRegistry = .imageRoot.registry -}} +{{- end -}} + +{{- $registry := $localRegistry | default $globalRegistry | default .defaultRegistry -}} +{{- if $registry -}} + {{- $registry -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image repository +{{ include "newrelic.common.images.repository" .Values.path.to.the.image }} +*/ -}} +{{- define "newrelic.common.images.repository" -}} + {{- .repository -}} +{{- end -}} + + + +{{- /* +Return the proper image tag +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.tag" -}} + {{- .imageRoot.tag | default .context.Chart.AppVersion | toString -}} +{{- end -}} + + + +{{- /* +Return the proper Image Pull Registry Secret Names evaluating values as templates +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.path.to.the.images.pullSecrets1, .Values.path.to.the.images.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- if .context.Values.global.images.pullSecrets -}} + {{- range .context.Values.global.images.pullSecrets -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- range .pullSecrets -}} + {{- if not (empty .) -}} + {{- range . -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if $flatlist -}} + {{- toYaml $flatlist -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_insights.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_insights.tpl new file mode 100644 index 000000000..895c37732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_insights.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the Insights Key. +*/}} +{{- define "newrelic.common.insightsKey.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "insightskey" ) -}} +{{- include "newrelic.common.insightsKey._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +*/}} +{{- define "newrelic.common.insightsKey.secretKeyName" -}} +{{- include "newrelic.common.insightsKey._customSecretKey" . | default "insightsKey" -}} +{{- end -}} + +{{/* +Return local insightsKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._licenseKey" -}} +{{- if .Values.insightsKey -}} + {{- .Values.insightsKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.insightsKey -}} + {{- .Values.global.insightsKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the Insights Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretName" -}} +{{- if .Values.customInsightsKeySecretName -}} + {{- .Values.customInsightsKeySecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretName -}} + {{- .Values.global.customInsightsKeySecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretKey" -}} +{{- if .Values.customInsightsKeySecretKey -}} + {{- .Values.customInsightsKeySecretKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretKey }} + {{- .Values.global.customInsightsKeySecretKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_insights_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_insights_secret.yaml.tpl new file mode 100644 index 000000000..556caa6ca --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_insights_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the insights key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.insightsKey.secret" }} +{{- if not (include "newrelic.common.insightsKey._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.insightsKey._licenseKey" .) }} + {{- fail "You must specify a insightsKey or a customInsightsSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.insightsKey.secretKeyName" . }}: {{ include "newrelic.common.insightsKey._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_labels.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_labels.tpl @@ -0,0 +1,54 @@ +{{/* +This will render the labels that should be used in all the manifests used by the helm chart. +*/}} +{{- define "newrelic.common.labels" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- $chart := dict "helm.sh/chart" (include "newrelic.common.naming.chart" . ) -}} +{{- $managedBy := dict "app.kubernetes.io/managed-by" .Release.Service -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $labels := mustMergeOverwrite $chart $managedBy $selectorLabels -}} +{{- if .Chart.AppVersion -}} +{{- $labels = mustMergeOverwrite $labels (dict "app.kubernetes.io/version" .Chart.AppVersion) -}} +{{- end -}} + +{{- $globalUserLabels := $global.labels | default dict -}} +{{- $localUserLabels := .Values.labels | default dict -}} + +{{- $labels = mustMergeOverwrite $labels $globalUserLabels $localUserLabels -}} + +{{- toYaml $labels -}} +{{- end -}} + + + +{{/* +This will render the labels that should be used in deployments/daemonsets template pods as a selector. +*/}} +{{- define "newrelic.common.labels.selectorLabels" -}} +{{- $name := dict "app.kubernetes.io/name" ( include "newrelic.common.naming.name" . ) -}} +{{- $instance := dict "app.kubernetes.io/instance" .Release.Name -}} + +{{- $selectorLabels := mustMergeOverwrite $name $instance -}} + +{{- toYaml $selectorLabels -}} +{{- end }} + + + +{{/* +Pod labels +*/}} +{{- define "newrelic.common.labels.podLabels" -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $global := index .Values "global" | default dict -}} +{{- $globalPodLabels := $global.podLabels | default dict }} + +{{- $localPodLabels := .Values.podLabels | default dict }} + +{{- $podLabels := mustMergeOverwrite $selectorLabels $globalPodLabels $localPodLabels -}} + +{{- toYaml $podLabels -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_license.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..647b4ff43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_license.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "license" ) -}} +{{- include "newrelic.common.license._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +*/}} +{{- define "newrelic.common.license.secretKeyName" -}} +{{- include "newrelic.common.license._customSecretKey" . | default "licenseKey" -}} +{{- end -}} + +{{/* +Return local licenseKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._licenseKey" -}} +{{- if .Values.licenseKey -}} + {{- .Values.licenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.licenseKey -}} + {{- .Values.global.licenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the License Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretName" -}} +{{- if .Values.customSecretName -}} + {{- .Values.customSecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretName -}} + {{- .Values.global.customSecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretKey" -}} +{{- if .Values.customSecretLicenseKey -}} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_license_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_license_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the license key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.license.secret" }} +{{- if not (include "newrelic.common.license._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.license._licenseKey" .) }} + {{- fail "You must specify a licenseKey or a customSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.license.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.license.secretKeyName" . }}: {{ include "newrelic.common.license._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_low-data-mode.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_low-data-mode.tpl @@ -0,0 +1,26 @@ +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..19fa92648 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_naming.tpl @@ -0,0 +1,73 @@ +{{/* +This is an function to be called directly with a string just to truncate strings to +63 chars because some Kubernetes name fields are limited to that. +*/}} +{{- define "newrelic.common.naming.truncateToDNS" -}} +{{- . | trunc 63 | trimSuffix "-" }} +{{- end }} + + + +{{- /* +Given a name and a suffix returns a 'DNS Valid' which always include the suffix, truncating the name if needed. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If suffix is too long it gets truncated but it always takes precedence over name, so a 63 chars suffix would suppress the name. +Usage: +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "" "suffix" "my-suffix" ) }} +*/ -}} +{{- define "newrelic.common.naming.truncateToDNSWithSuffix" -}} +{{- $suffix := (include "newrelic.common.naming.truncateToDNS" .suffix) -}} +{{- $maxLen := (max (sub 63 (add1 (len $suffix))) 0) -}} {{- /* We prepend "-" to the suffix so an additional character is needed */ -}} + +{{- $newName := .name | trunc ($maxLen | int) | trimSuffix "-" -}} +{{- if $newName -}} +{{- printf "%s-%s" $newName $suffix -}} +{{- else -}} +{{ $suffix }} +{{- end -}} + +{{- end -}} + + + +{{/* +Expand the name of the chart. +Uses the Chart name by default if nameOverride is not set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.name" -}} +{{- $name := .Values.nameOverride | default .Chart.Name -}} +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end }} + + + +{{/* +Create a default fully qualified app name. +By default the full name will be "" just in if it has the chart name included in that, if not +it will be concatenated like "-". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.fullname" -}} +{{- $name := include "newrelic.common.naming.name" . -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} + +{{- end -}} + + + +{{/* +Create chart name and version as used by the chart label. +This function should not be used for naming objects. Use "common.naming.{name,fullname}" instead. +*/}} +{{- define "newrelic.common.naming.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_nodeselector.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_nodeselector.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod nodeSelector */ -}} +{{- define "newrelic.common.nodeSelector" -}} + {{- if .Values.nodeSelector -}} + {{- toYaml .Values.nodeSelector -}} + {{- else if .Values.global -}} + {{- if .Values.global.nodeSelector -}} + {{- toYaml .Values.global.nodeSelector -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_priority-class-name.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_priority-class-name.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the pod priorityClassName */ -}} +{{- define "newrelic.common.priorityClassName" -}} + {{- if .Values.priorityClassName -}} + {{- .Values.priorityClassName -}} + {{- else if .Values.global -}} + {{- if .Values.global.priorityClassName -}} + {{- .Values.global.priorityClassName -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_privileged.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_privileged.tpl @@ -0,0 +1,28 @@ +{{- /* +This is a helper that returns whether the chart should assume the user is fine deploying privileged pods. +*/ -}} +{{- define "newrelic.common.privileged" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists. */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values "privileged" | kindIs "bool" -}} + {{- if .Values.privileged -}} + {{- .Values.privileged -}} + {{- end -}} +{{- else if get $global "privileged" | kindIs "bool" -}} + {{- if $global.privileged -}} + {{- $global.privileged -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* Return directly "true" or "false" based in the exist of "newrelic.common.privileged" */ -}} +{{- define "newrelic.common.privileged.value" -}} +{{- if include "newrelic.common.privileged" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_proxy.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_proxy.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the proxy */ -}} +{{- define "newrelic.common.proxy" -}} + {{- if .Values.proxy -}} + {{- .Values.proxy -}} + {{- else if .Values.global -}} + {{- if .Values.global.proxy -}} + {{- .Values.global.proxy -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_security-context.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_security-context.tpl @@ -0,0 +1,23 @@ +{{- /* Defines the container securityContext context */ -}} +{{- define "newrelic.common.securityContext.container" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.containerSecurityContext -}} + {{- toYaml .Values.containerSecurityContext -}} +{{- else if $global.containerSecurityContext -}} + {{- toYaml $global.containerSecurityContext -}} +{{- end -}} +{{- end -}} + + + +{{- /* Defines the pod securityContext context */ -}} +{{- define "newrelic.common.securityContext.pod" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.podSecurityContext -}} + {{- toYaml .Values.podSecurityContext -}} +{{- else if $global.podSecurityContext -}} + {{- toYaml $global.podSecurityContext -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_serviceaccount.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..2d352f6ea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_serviceaccount.tpl @@ -0,0 +1,90 @@ +{{- /* Defines if the service account has to be created or not */ -}} +{{- define "newrelic.common.serviceAccount.create" -}} +{{- $valueFound := false -}} + +{{- /* Look for a global creation of a service account */ -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "create" | kindIs "bool") -}} + {{- $valueFound = true -}} + {{- if .Values.serviceAccount.create -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.serviceAccount.name" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.serviceAccount.create -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Look for a local creation of a service account */ -}} +{{- if not $valueFound -}} + {{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} + {{- $global := index .Values "global" | default dict -}} + {{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "create" | kindIs "bool" -}} + {{- $valueFound = true -}} + {{- if $global.serviceAccount.create -}} + {{- $global.serviceAccount.create -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* In case no serviceAccount value has been found, default to "true" */ -}} +{{- if not $valueFound -}} +true +{{- end -}} +{{- end -}} + + + +{{- /* Defines the name of the service account */ -}} +{{- define "newrelic.common.serviceAccount.name" -}} +{{- $localServiceAccount := "" -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "name" | kindIs "string") -}} + {{- $localServiceAccount = .Values.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := "" -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "name" | kindIs "string" -}} + {{- $globalServiceAccount = $global.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- if (include "newrelic.common.serviceAccount.create" .) -}} + {{- $localServiceAccount | default $globalServiceAccount | default (include "newrelic.common.naming.fullname" .) -}} +{{- else -}} + {{- $localServiceAccount | default $globalServiceAccount | default "default" -}} +{{- end -}} +{{- end -}} + + + +{{- /* Merge the global and local annotations for the service account */ -}} +{{- define "newrelic.common.serviceAccount.annotations" -}} +{{- $localServiceAccount := dict -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if get .Values.serviceAccount "annotations" -}} + {{- $localServiceAccount = .Values.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := dict -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "annotations" -}} + {{- $globalServiceAccount = $global.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $merged := mustMergeOverwrite $globalServiceAccount $localServiceAccount -}} + +{{- if $merged -}} + {{- toYaml $merged -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_staging.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_staging.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the nrStaging toggle. +This helper allows to override the global `.global.nrStaging` with the value of `.nrStaging`. +Returns "true" if `nrStaging` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.nrStaging" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "nrStaging" | kindIs "bool") -}} + {{- if .Values.nrStaging -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.nrStaging" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.nrStaging -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "nrStaging" | kindIs "bool" -}} + {{- if $global.nrStaging -}} + {{- $global.nrStaging -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Returns "true" of "false" directly instead of empty string (Helm falsiness) based on the exit of "newrelic.common.nrStaging" +*/ -}} +{{- define "newrelic.common.nrStaging.value" -}} +{{- if include "newrelic.common.nrStaging" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_tolerations.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_tolerations.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod tolerations */ -}} +{{- define "newrelic.common.tolerations" -}} + {{- if .Values.tolerations -}} + {{- toYaml .Values.tolerations -}} + {{- else if .Values.global -}} + {{- if .Values.global.tolerations -}} + {{- toYaml .Values.global.tolerations -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_verbose-log.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/templates/_verbose-log.tpl @@ -0,0 +1,54 @@ +{{- /* +Abstraction of the verbose toggle. +This helper allows to override the global `.global.verboseLog` with the value of `.verboseLog`. +Returns "true" if `verbose` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.verboseLog" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "verboseLog" | kindIs "bool") -}} + {{- if .Values.verboseLog -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.verboseLog" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.verboseLog -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "verboseLog" | kindIs "bool" -}} + {{- if $global.verboseLog -}} + {{- $global.verboseLog -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return true or false directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsBoolean" -}} +{{- if include "newrelic.common.verboseLog" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return 1 or 0 directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsInt" -}} +{{- if include "newrelic.common.verboseLog" . -}} +1 +{{- else -}} +0 +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/charts/common-library/values.yaml @@ -0,0 +1 @@ +# values are not needed for the library chart, however this file is still needed for helm lint to work. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-enable-windows-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-enable-windows-values.yaml new file mode 100644 index 000000000..870bc082a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-enable-windows-values.yaml @@ -0,0 +1,2 @@ +enableLinux: false +enableWindows: true diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-lowdatamode-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-lowdatamode-values.yaml new file mode 100644 index 000000000..7740338b0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-lowdatamode-values.yaml @@ -0,0 +1 @@ +lowDataMode: true diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-override-global-lowdatamode.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-override-global-lowdatamode.yaml new file mode 100644 index 000000000..22dd7e05e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-override-global-lowdatamode.yaml @@ -0,0 +1,3 @@ +global: + lowDataMode: true +lowDataMode: false diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-staging-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-staging-values.yaml new file mode 100644 index 000000000..efbdccaf8 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-staging-values.yaml @@ -0,0 +1 @@ +nrStaging: true diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-with-empty-global.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-with-empty-global.yaml new file mode 100644 index 000000000..490a0b7ed --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-with-empty-global.yaml @@ -0,0 +1 @@ +global: {} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-with-empty-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/ci/test-with-empty-values.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/fluent-bit-and-plugin-metrics-dashboard-template.json b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/fluent-bit-and-plugin-metrics-dashboard-template.json new file mode 100644 index 000000000..cafdaf85c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/fluent-bit-and-plugin-metrics-dashboard-template.json @@ -0,0 +1,2237 @@ +{ + "name": "Kubernetes Fluent Bit monitoring", + "description": null, + "permissions": "PUBLIC_READ_WRITE", + "pages": [ + { + "name": "Fluent Bit metrics: General", + "description": null, + "widgets": [ + { + "title": "", + "layout": { + "column": 1, + "row": 1, + "width": 6, + "height": 6 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# README\n\n## About this page\nThis page represents most of [Fluent Bit's internal metrics](https://docs.fluentbit.io/manual/administration/monitoring#for-v2-metrics). The metric representations are grouped by categories and faceted by each plugin instance where appropriate.\n\n## How to filter\n1. Select the Kubernetes cluster you want to troubleshoot in the \"Cluster Name\" variable above.\n2. [OPTIONAL] You can use any of the values in the `Node name` and `Pod name` columns on the \"Fluent Bit version\" table to further filter the metrics displayed in the graphs below. To do so, you need to enable [facet filtering](https://docs.newrelic.com/docs/query-your-data/explore-query-data/dashboards/filter-new-relic-one-dashboards-facets/) on that table by clicking on the \"Edit\" submenu and select \"Filter the current dashboard\" under \"Facet Linking\". \n\n## Legend\n### Metric dimensions\n- **name**: the name of the Fluent Bit plugin. Version 1.21.0 of our Helm chart names them according to the plugin names described in the following section.\n- **pod_name**: the `newrelic-logging` pod (Fluent Bit instance) that emitted this metric.\n- **node_name**: physical Kubernetes node where the `newrelic-logging` pod is running.\n\n### Plugin names\n- **pod-logs-tailer**: `tail` *INPUT* plugin normally reading from `/var/log/containers/*.log`\n- **kubernetes-enricher**: `kubernetes` *FILTER* plugin that queries the Kubernetes API to enrich the logs with pod/container metadata.\n- **node-attributes-enricher**: `record_modifier` *FILTER* plugin that enriches logs with `cluster_name`.\n- **kubernetes-attribute-lifter** (only when in low data mode): `nest` *FILTER* plugin that lifts all the keys under `kubernetes`. This plugin is transparent to the final shape of the log.\n- **node-attributes-enricher-filter** (only when in low data mode): same as node-attributes-enricher`, but it also removes attributes that are not strictly necessary for correct platform functioning.\n- **newrelic-logs-forwarder**: `newrelic` *OUTPUT* plugin that sends logs to the New Relic Logs API" + } + }, + { + "title": "Fluent Bit version", + "layout": { + "column": 7, + "row": 1, + "width": 6, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.table" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT latest(os) as 'OS', latest(version) as 'FB version', latest(cluster_name) FROM Metric where metricName = 'fluentbit_build_info' AND cluster_name IN ({{cluster_name}}) since 1 hour ago facet pod_name, node_name limit max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Fluent Bit uptime", + "layout": { + "column": 7, + "row": 4, + "width": 6, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT latest(fluentbit_uptime) FROM Metric where cluster_name IN ({{cluster_name}}) facet pod_name timeseries" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "", + "layout": { + "column": 1, + "row": 7, + "width": 12, + "height": 1 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# INPUTS" + } + }, + { + "title": "Input byte rate (bytes/minute)", + "layout": { + "column": 1, + "row": 8, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_input_bytes_total), 1 minute) as 'bytes/minute' FROM Metric where name != 'fb-metrics-collector' and cluster_name IN ({{cluster_name}}) timeseries max facet name, pod_name" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Input log rate (records/minute)", + "layout": { + "column": 5, + "row": 8, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_input_records_total), 1 minute) as 'logs/minute' FROM Metric where name != 'fb-metrics-collector' and cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Average incoming record size (bytes)", + "layout": { + "column": 9, + "row": 8, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT sum(fluentbit_input_bytes_total)/sum(fluentbit_input_records_total) as 'Average incoming record size (bytes)' FROM Metric where name != 'fb-metrics-collector' and cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "", + "layout": { + "column": 1, + "row": 11, + "width": 12, + "height": 1 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# FILTERS" + } + }, + { + "title": "Filter byte rate (bytes/minute)", + "layout": { + "column": 1, + "row": 12, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_filter_bytes_total), 1 minute) FROM Metric WHERE cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Filter log rate (records/minute)", + "layout": { + "column": 5, + "row": 12, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_filter_records_total), 1 minute) FROM Metric WHERE cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Average filtered record size (bytes)", + "layout": { + "column": 9, + "row": 12, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT sum(fluentbit_filter_bytes_total)/sum(fluentbit_filter_records_total) AS 'Average filtered record size (bytes)' FROM Metric WHERE cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Record add/drop rate per FILTER plugin", + "layout": { + "column": 1, + "row": 15, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_filter_add_records_total), 1 minute) as 'Added back to pipeline', rate(sum(fluentbit_filter_drop_records_total), 1 minute) as 'Removed from pipeline' FROM Metric WHERE cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries MAX" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "REQUESTS_PER_MINUTE" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "", + "layout": { + "column": 1, + "row": 18, + "width": 12, + "height": 1 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# OUTPUTS" + } + }, + { + "title": "Output byte rate (bytes/minute)", + "layout": { + "column": 1, + "row": 19, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_proc_bytes_total), 1 minute) as 'bytes/minute' FROM Metric where cluster_name IN ({{cluster_name}}) AND name != 'fb-metrics-forwarder' facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Output log rate (records/minute)", + "layout": { + "column": 5, + "row": 19, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_proc_records_total), 1 minute) as 'records/minute' FROM Metric where cluster_name IN ({{cluster_name}}) AND name != 'fb-metrics-forwarder' facet name, pod_name timeseries MAX " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Average outgoing record size (bytes)", + "layout": { + "column": 9, + "row": 19, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT sum(fluentbit_output_proc_bytes_total)/sum(fluentbit_output_proc_records_total) as 'bytes' FROM Metric where cluster_name IN ({{cluster_name}}) AND name != 'fb-metrics-forwarder' facet name, pod_name timeseries MAX" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "newrelic plugin statistics (records/minute)", + "layout": { + "column": 1, + "row": 22, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_proc_records_total), 1 minute) as 'Processed', rate(sum(fluentbit_output_dropped_records_total), 1 minute) as 'Dropped', rate(sum(fluentbit_output_retried_records_total), 1 minute) as 'Retried' FROM Metric where cluster_name IN ({{cluster_name}}) AND name = 'newrelic-logs-forwarder' facet pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Other OUTPUT plugin statistics (records/minute)", + "layout": { + "column": 5, + "row": 22, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_proc_records_total), 1 minute) as 'Processed', rate(sum(fluentbit_output_dropped_records_total), 1 minute) as 'Dropped', rate(sum(fluentbit_output_retried_records_total), 1 minute) as 'Retried' FROM Metric where cluster_name IN ({{cluster_name}}) AND name != 'newrelic-logs-forwarder' and name != 'fb-metrics-forwarder' facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Connections per OUTPUT plugin", + "layout": { + "column": 9, + "row": 22, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT max(fluentbit_output_upstream_total_connections) as 'Total', max(fluentbit_output_upstream_busy_connections) as 'Busy' FROM Metric where cluster_name IN ({{cluster_name}}) AND name != 'fb-metrics-forwarder' facet name, pod_name timeseries MAX" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "newrelic plugin errors (errors/minute)", + "layout": { + "column": 1, + "row": 25, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_errors_total), 1 minute) AS 'Errors/minute' FROM Metric where cluster_name IN ({{cluster_name}}) AND name = 'newrelic-logs-forwarder' facet pod_name timeseries MAX " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "newrelic plugin chunk retry statistics (retries/minute)", + "layout": { + "column": 5, + "row": 25, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_retries_total), 1 minute) as 'Retries', rate(sum(fluentbit_output_retries_failed_total), 1 minute) as 'Expirations' FROM Metric where cluster_name IN ({{cluster_name}}) AND name = 'newrelic-logs-forwarder' facet pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "", + "layout": { + "column": 1, + "row": 28, + "width": 12, + "height": 1 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# MEMORY USAGE" + } + }, + { + "title": "Input plugin memory usage", + "layout": { + "column": 1, + "row": 29, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT max(fluentbit_input_storage_memory_bytes) as 'Max' FROM Metric where cluster_name IN ({{cluster_name}}) and name != 'fb-metrics-collector' timeseries max facet name, pod_name " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "INPUT memory buffer over limit", + "layout": { + "column": 5, + "row": 29, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "colors": { + "seriesOverrides": [ + { + "color": "#013ef4", + "seriesName": "pod-logs-tailer" + } + ] + }, + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT max(fluentbit_input_storage_overlimit) FROM Metric where cluster_name IN ({{cluster_name}}) and name != 'fb-metrics-collector' timeseries max facet name, pod_name" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true, + "thresholds": [ + { + "from": 0.95, + "name": "Mem buf overlimit", + "severity": "critical", + "to": 1.05 + } + ] + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Chunk statistics per INPUT plugin", + "layout": { + "column": 9, + "row": 29, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT average(fluentbit_input_storage_chunks_up) AS 'Up (in memory)', average(fluentbit_input_storage_chunks_down) AS 'Down (in fs)', average(fluentbit_input_storage_chunks_busy) AS 'Busy', average(fluentbit_input_storage_chunks) as 'Total' FROM Metric where name != 'fb-metrics-collector' since 1 hour ago timeseries MAX facet name, pod_name " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Buffered chunks", + "layout": { + "column": 1, + "row": 32, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT max(fluentbit_input_storage_chunks) AS 'Total', max(fluentbit_storage_mem_chunks) AS 'Memory', max(fluentbit_storage_fs_chunks) AS 'Filesystem' FROM Metric where cluster_name IN ({{cluster_name}}) facet pod_name timeseries MAX " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Busy chunks' size", + "layout": { + "column": 5, + "row": 32, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT max(fluentbit_input_storage_chunks_busy_bytes) FROM Metric where name != 'fb-metrics-collector' facet name, pod_name timeseries MAX since 1 hour ago" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Filesystem chunks state", + "layout": { + "column": 9, + "row": 32, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT average(fluentbit_storage_fs_chunks_up) AS 'Up (in memory)', average(fluentbit_storage_fs_chunks_down) AS 'Down (fs only)' FROM Metric since '2024-02-29 13:22:00+0000' UNTIL '2024-02-29 14:31:00+0000' timeseries MAX " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + } + ] + }, + { + "name": "Fluent Bit metrics: Pipeline View", + "description": null, + "widgets": [ + { + "title": "", + "layout": { + "column": 1, + "row": 1, + "width": 6, + "height": 6 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# README\n\n## About this page\nThis page represents the same metrics that are displayed in the \"Fluent Bit metrics: General\" page. Nevertheless, they are grouped differently to allow you to visualize a given metric across the whole pipeline with a single glance.\n\n## How to filter\n1. Select the Kubernetes cluster you want to troubleshoot in the \"Cluster Name\" variable above.\n2. [OPTIONAL] You can use any of the values in the `Node name` and `Pod name` columns on the \"Fluent Bit version\" table to further filter the metrics displayed in the graphs below. To do so, you need to enable [facet filtering](https://docs.newrelic.com/docs/query-your-data/explore-query-data/dashboards/filter-new-relic-one-dashboards-facets/) on that table by clicking on the \"Edit\" submenu and select \"Filter the current dashboard\" under \"Facet Linking\". \n\n## Legend\n### Metric dimensions\n- **name**: the name of the Fluent Bit plugin. Version 1.21.0 of our Helm chart names them according to the plugin names described in the following section.\n- **pod_name**: the `newrelic-logging` pod (Fluent Bit instance) that emitted this metric.\n- **node_name**: physical Kubernetes node where the `newrelic-logging` pod is running.\n\n### Plugin names\n- **pod-logs-tailer**: `tail` *INPUT* plugin normally reading from `/var/log/containers/*.log`\n- **kubernetes-enricher**: `kubernetes` *FILTER* plugin that queries the Kubernetes API to enrich the logs with pod/container metadata.\n- **node-attributes-enricher**: `record_modifier` *FILTER* plugin that enriches logs with `cluster_name`.\n- **kubernetes-attribute-lifter** (only when in low data mode): `nest` *FILTER* plugin that lifts all the keys under `kubernetes`. This plugin is transparent to the final shape of the log.\n- **node-attributes-enricher-filter** (only when in low data mode): same as node-attributes-enricher`, but it also removes attributes that are not strictly necessary for correct platform functioning.\n- **newrelic-logs-forwarder**: `newrelic` *OUTPUT* plugin that sends logs to the New Relic Logs API" + } + }, + { + "title": "Fluent Bit version", + "layout": { + "column": 7, + "row": 1, + "width": 6, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.table" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT latest(os) as 'OS', latest(version) as 'FB version', latest(cluster_name) FROM Metric where metricName = 'fluentbit_build_info' AND cluster_name IN ({{cluster_name}}) since 1 hour ago facet pod_name, node_name limit max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + } + } + }, + { + "title": "Fluent Bit uptime", + "layout": { + "column": 7, + "row": 4, + "width": 6, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT latest(fluentbit_uptime) FROM Metric where cluster_name IN ({{cluster_name}}) timeseries facet pod_name " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "SECONDS" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "", + "layout": { + "column": 1, + "row": 7, + "width": 12, + "height": 1 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# BYTE RATES" + } + }, + { + "title": "Input byte rate (bytes/minute)", + "layout": { + "column": 1, + "row": 8, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_input_bytes_total), 1 minute) as 'bytes/minute' FROM Metric where name != 'fb-metrics-collector' and cluster_name IN ({{cluster_name}}) timeseries max facet name, pod_name" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Filter byte rate (bytes/minute)", + "layout": { + "column": 5, + "row": 8, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_filter_bytes_total), 1 minute) FROM Metric WHERE cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Output byte rate (bytes/minute)", + "layout": { + "column": 9, + "row": 8, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_proc_bytes_total), 1 minute) as 'bytes/minute' FROM Metric where cluster_name IN ({{cluster_name}}) AND name != 'fb-metrics-forwarder' facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "", + "layout": { + "column": 1, + "row": 11, + "width": 12, + "height": 1 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# LOG RECORD RATES" + } + }, + { + "title": "Input log rate (records/minute)", + "layout": { + "column": 1, + "row": 12, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_input_records_total), 1 minute) as 'logs/minute' FROM Metric where name != 'fb-metrics-collector' and cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Filter log rate (records/minute)", + "layout": { + "column": 5, + "row": 12, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_filter_records_total), 1 minute) FROM Metric WHERE cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Output log rate (records/minute)", + "layout": { + "column": 9, + "row": 12, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_proc_records_total), 1 minute) as 'records/minute' FROM Metric where cluster_name IN ({{cluster_name}}) AND name != 'fb-metrics-forwarder' facet name, pod_name timeseries MAX " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Record add/drop rate per FILTER plugin", + "layout": { + "column": 5, + "row": 15, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_filter_add_records_total), 1 minute) as 'Added back to pipeline', rate(sum(fluentbit_filter_drop_records_total), 1 minute) as 'Removed from pipeline' FROM Metric WHERE cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries MAX" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "REQUESTS_PER_MINUTE" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "", + "layout": { + "column": 1, + "row": 18, + "width": 12, + "height": 1 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# AVERAGE LOG RECORD SIZES AT THE END OF EACH STAGE" + } + }, + { + "title": "Average incoming record size (bytes)", + "layout": { + "column": 1, + "row": 19, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT sum(fluentbit_input_bytes_total)/sum(fluentbit_input_records_total) as 'Average incoming record size (bytes)' FROM Metric where name != 'fb-metrics-collector' and cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Average filtered record size (bytes)", + "layout": { + "column": 5, + "row": 19, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT sum(fluentbit_filter_bytes_total)/sum(fluentbit_filter_records_total) AS 'Average filtered record size (bytes)' FROM Metric WHERE cluster_name IN ({{cluster_name}}) facet name, pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Average outgoing record size (bytes)", + "layout": { + "column": 9, + "row": 19, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT sum(fluentbit_output_proc_bytes_total)/sum(fluentbit_output_proc_records_total) as 'bytes' FROM Metric where cluster_name IN ({{cluster_name}}) AND name != 'fb-metrics-forwarder' facet name, pod_name timeseries MAX" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "", + "layout": { + "column": 1, + "row": 22, + "width": 12, + "height": 1 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# MEMORY USAGE AND BACKPRESSURE" + } + }, + { + "title": "Input plugin memory usage", + "layout": { + "column": 1, + "row": 23, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT max(fluentbit_input_storage_memory_bytes) as 'Max' FROM Metric where cluster_name IN ({{cluster_name}}) and name != 'fb-metrics-collector' timeseries max facet name, pod_name " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Busy chunks' size", + "layout": { + "column": 5, + "row": 23, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT max(fluentbit_input_storage_chunks_busy_bytes) FROM Metric where name != 'fb-metrics-collector' facet name, pod_name timeseries MAX since 1 hour ago" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "newrelic plugin chunk retry statistics (retries/minute)", + "layout": { + "column": 9, + "row": 23, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_retries_total), 1 minute) as 'Retries', rate(sum(fluentbit_output_retries_failed_total), 1 minute) as 'Expirations' FROM Metric where cluster_name IN ({{cluster_name}}) AND name = 'newrelic-logs-forwarder' facet pod_name timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "INPUT memory buffer over limit", + "layout": { + "column": 1, + "row": 26, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "colors": { + "seriesOverrides": [ + { + "color": "#013ef4", + "seriesName": "pod-logs-tailer" + } + ] + }, + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT max(fluentbit_input_storage_overlimit) FROM Metric where cluster_name IN ({{cluster_name}}) and name != 'fb-metrics-collector' timeseries max facet name, pod_name" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true, + "thresholds": [ + { + "from": 0.95, + "name": "Mem buf overlimit", + "severity": "critical", + "to": 1.05 + } + ] + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Chunk statistics per INPUT plugin", + "layout": { + "column": 5, + "row": 26, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT average(fluentbit_input_storage_chunks_up) AS 'Up (in memory)', average(fluentbit_input_storage_chunks_down) AS 'Down (in fs)', average(fluentbit_input_storage_chunks_busy) AS 'Busy', average(fluentbit_input_storage_chunks) as 'Total' FROM Metric where name != 'fb-metrics-collector' since 1 hour ago timeseries MAX facet name, pod_name " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "newrelic plugin errors (errors/minute)", + "layout": { + "column": 9, + "row": 26, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(fluentbit_output_errors_total), 1 minute) AS 'Errors/minute' FROM Metric where cluster_name IN ({{cluster_name}}) AND name = 'newrelic-logs-forwarder' facet pod_name timeseries MAX " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": { + "isLabelVisible": true + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + } + ] + }, + { + "name": "newrelic-fluent-bit-output plugin metrics", + "description": null, + "widgets": [ + { + "title": "", + "layout": { + "column": 1, + "row": 1, + "width": 4, + "height": 9 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.markdown" + }, + "rawConfiguration": { + "text": "# README\n## About this page\nThis page displays metrics collected internally in the [New Relic Fluent Bit output plugin](https://github.com/newrelic/newrelic-fluent-bit-output) (in short, **NR FB plugin**). These metrics are independent of Fluent Bit's, and **must not be considered as a stable API: they can change its naming or dimensions at any time in newer plugin versions**.\n\nPlease note that **the NR FB plugin does not include the `pod_name` nor the `node_name` dimensions**. Therefore, the graphs below represent an aggregation of all your running Fluent Bit instances across one or more clusters. You can use the `cluster_name` dimension (or dashboard variable above) to narrow down the troubleshooting to one or more clusters.\n\n## Basic naming conventions\n- Fluent Bit aggregates logs in batches, also referred as **[chunks](https://docs.fluentbit.io/manual/administration/buffering-and-storage#chunks-memory-filesystem-and-backpressure)**. Each chunk therefore contains an unknown amount of logs.\n- Chunks are received sequentially at the NR FB plugin, which takes care of reading the logs they contain and splitting them into the so-called New Relic *payloads*.\n- Each **payload** is a compressed stream of bytes that can be [at most 1MB long](https://docs.newrelic.com/docs/logs/log-api/introduction-log-api/#limits), and follows the [data format required by the Logs API](https://docs.newrelic.com/docs/logs/log-api/introduction-log-api/#json-content).\n\n\n## Error-detection graphs and recommended actions\n\nThe following are the main graphs used to detect potential problems in your log forwarding setup. Refer to each section to learn the recommended actions for each graph.\n\n### Payload packaging errors\nRepresents the percentage of Fluent Bit chunks that threw an error when they were attempted to be packaged as New Relic payloads. Such errors are never expected to happen. Therefore, **any value greater than 0% should be thoroughly investigated**.\n\nIf you find errors in this graph, please open a support ticket and include a sample of your logs for further investigation.\n\n### Payload sending errors\nRepresents the percentage of New Relic payloads that threw an unexpected error when they were attempted to be sent to New Relic. Such errors can happen sporadically: timeouts due to poor network performance or sudden network changes can cause them from time to time. Observing **values greater than 0% can sometimes be normal, but any value above 10% should be considered as an annomalous situation and should be thoroughly investigated**.\n\nIf you find errors in this graph, please ensure that you don't have any weak spots in your network path to New Relic: are you using a proxy? Is it or any network hop introducing too much latency due to being saturated? If you can't find anything on you side, please open a support ticket and include as much information as possible from your network setup.\n\n### Payload send results\nRepresents the amount of API requests that were performed to send logs to New Relic. **Ideally, you should only observe 202 responses here**. Sometimes, intermediary CDN providers can introduce some errors (503 error codes) from time to time, in which case your logs will not be lost and reattempted to be sent.\n\nIf you find a considerable amount of non-202 responses in this graph, please open a customer support ticket.\n\n## Additional troubleshooting graphs\n\nThe following graphs include additional fine-grained information that will be useful for New Relic to troubleshoot your potential installation issues.\n\n### Average timings\nRepresents the average amount of time the plugin spent packaging the log payloads and sending them to New Relic, respectively.\n\n### Accumulated time per minute\nRepresents the amount of time per minute the plugin spent packaging the log payloads and sending them to New Relic, respectively.\n\n### Payload size\nRepresents the size in bytes of the individual compressed payloads sent to New Relic.\n\n### Payload packets per Fluent Bit chunk\nRepresents the amount of payloads sent to New Relic per each Fluent Bit chunk." + } + }, + { + "title": "Payload packaging errors", + "layout": { + "column": 5, + "row": 1, + "width": 2, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.billboard" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "FROM Metric SELECT percentage(count(`logs.fb.packaging.time`), WHERE hasError = true) AS 'packaging errors'" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": [ + { + "alertSeverity": "CRITICAL", + "value": 0 + } + ] + } + }, + { + "title": "Payload sending errors", + "layout": { + "column": 7, + "row": 1, + "width": 2, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.billboard" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "FROM Metric SELECT percentage(count(`logs.fb.payload.send.time`), WHERE hasError = true) AS 'send errors'" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "thresholds": [ + { + "alertSeverity": "WARNING", + "value": 0 + }, + { + "alertSeverity": "CRITICAL", + "value": 0.1 + } + ] + } + }, + { + "title": "Payload send results", + "layout": { + "column": 9, + "row": 1, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(count(logs.fb.payload.send.time), 1 minute) AS 'Status Code' FROM Metric FACET CASES(WHERE statusCode = 0 AS 'Send error') OR statusCode timeseries max" + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "units": { + "unit": "REQUESTS_PER_MINUTE" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Average timings", + "layout": { + "column": 5, + "row": 4, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT average(logs.fb.payload.send.time) AS 'Payload sending', average(logs.fb.packaging.time) AS 'Payload packaging' FROM Metric timeseries max" + } + ], + "nullValues": { + "nullValue": "zero" + }, + "platformOptions": { + "ignoreTimeRange": false + }, + "units": { + "unit": "MS" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Accumulated time per minute", + "layout": { + "column": 9, + "row": 4, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.area" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT rate(sum(logs.fb.total.send.time), 1 minute) AS 'Sending', rate(sum(logs.fb.packaging.time), 1 minute) AS 'Packaging' FROM Metric TIMESERIES max" + } + ], + "nullValues": { + "nullValue": "zero" + }, + "platformOptions": { + "ignoreTimeRange": false + }, + "units": { + "unit": "MS" + } + } + }, + { + "title": "Payload size", + "layout": { + "column": 5, + "row": 7, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT min(logs.fb.payload.size) AS 'Minimum', average(logs.fb.payload.size) AS 'Average', max(logs.fb.payload.size) AS 'Maximum' FROM Metric timeseries MAX " + } + ], + "nullValues": { + "nullValue": "default" + }, + "platformOptions": { + "ignoreTimeRange": false + }, + "units": { + "unit": "BYTES" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + }, + { + "title": "Payload packets per Fluent Bit chunk", + "layout": { + "column": 9, + "row": 7, + "width": 4, + "height": 3 + }, + "linkedEntityGuids": null, + "visualization": { + "id": "viz.line" + }, + "rawConfiguration": { + "facet": { + "showOtherSeries": false + }, + "legend": { + "enabled": true + }, + "nrqlQueries": [ + { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT min(logs.fb.payload.count) AS 'Minimum', average(logs.fb.payload.count) AS 'Average', max(logs.fb.payload.count) AS 'Maximum' FROM Metric timeseries MAX " + } + ], + "platformOptions": { + "ignoreTimeRange": false + }, + "units": { + "unit": "COUNT" + }, + "yAxisLeft": { + "zero": true + }, + "yAxisRight": { + "zero": true + } + } + } + ] + } + ], + "variables": [ + { + "name": "cluster_name", + "items": null, + "defaultValues": [ + { + "value": { + "string": "*" + } + } + ], + "nrqlQuery": { + "accountIds": [ + YOUR_ACCOUNT_ID + ], + "query": "SELECT uniques(cluster_name) FROM Metric where metricName = 'fluentbit_input_storage_overlimit'" + }, + "options": { + "ignoreTimeRange": false + }, + "title": "Cluster Name", + "type": "NRQL", + "isMultiSelection": true, + "replacementStrategy": "STRING" + } + ] +} \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/NOTES.txt b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/NOTES.txt new file mode 100644 index 000000000..289f2157f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/NOTES.txt @@ -0,0 +1,18 @@ +{{- if (include "newrelic-logging.areValuesValid" .) }} +Your deployment of the New Relic Kubernetes Logging is complete. You can check on the progress of this by running the following command: + + kubectl get daemonset -o wide -w --namespace {{ .Release.Namespace }} {{ template "newrelic-logging.fullname" . }} +{{- else -}} +############################################################################## +#### ERROR: You did not set a license key. #### +############################################################################## + +This deployment will be incomplete until you get your API key from New Relic. + +Then run: + + helm upgrade {{ .Release.Name }} \ + --set licenseKey=(your-license-key) \ + newrelic/newrelic-logging + +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/_helpers.tpl new file mode 100644 index 000000000..439d25cae --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/_helpers.tpl @@ -0,0 +1,215 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "newrelic-logging.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 "newrelic-logging.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if ne $name .Release.Name -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + + +{{/* Generate basic labels */}} +{{- define "newrelic-logging.labels" }} +app: {{ template "newrelic-logging.name" . }} +chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +heritage: {{.Release.Service }} +release: {{.Release.Name }} +app.kubernetes.io/name: {{ template "newrelic-logging.name" . }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "newrelic-logging.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + + +{{/* +Create the name of the fluent bit config +*/}} +{{- define "newrelic-logging.fluentBitConfig" -}} +{{ template "newrelic-logging.fullname" . }}-fluent-bit-config +{{- end -}} + +{{/* +Return the licenseKey +*/}} +{{- define "newrelic-logging.licenseKey" -}} +{{- if .Values.global}} + {{- if .Values.global.licenseKey }} + {{- .Values.global.licenseKey -}} + {{- else -}} + {{- .Values.licenseKey | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.licenseKey | default "" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the cluster name +*/}} +{{- define "newrelic-logging.cluster" -}} +{{- if .Values.global}} + {{- if .Values.global.cluster }} + {{- .Values.global.cluster -}} + {{- else -}} + {{- .Values.cluster | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.cluster | default "" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the customSecretName +*/}} +{{- define "newrelic-logging.customSecretName" -}} +{{- if .Values.global }} + {{- if .Values.global.customSecretName }} + {{- .Values.global.customSecretName -}} + {{- else -}} + {{- .Values.customSecretName | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.customSecretName | default "" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the customSecretLicenseKey +*/}} +{{- define "newrelic-logging.customSecretKey" -}} +{{- if .Values.global }} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- else -}} + {{- if .Values.global.customSecretKey }} + {{- .Values.global.customSecretKey -}} + {{- else -}} + {{- .Values.customSecretKey | default "" -}} + {{- end -}} + {{- end -}} +{{- else -}} + {{- if .Values.customSecretLicenseKey }} + {{- .Values.customSecretLicenseKey -}} + {{- else -}} + {{- .Values.customSecretKey | default "" -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Returns nrStaging +*/}} +{{- define "newrelic.nrStaging" -}} +{{- if .Values.global }} + {{- if .Values.global.nrStaging }} + {{- .Values.global.nrStaging -}} + {{- end -}} +{{- else if .Values.nrStaging }} + {{- .Values.nrStaging -}} +{{- end -}} +{{- end -}} + +{{/* +Returns fargate +*/}} +{{- define "newrelic.fargate" -}} +{{- if .Values.global }} + {{- if .Values.global.fargate }} + {{- .Values.global.fargate -}} + {{- end -}} +{{- else if .Values.fargate }} + {{- .Values.fargate -}} +{{- end -}} +{{- end -}} + +{{/* +Returns lowDataMode +*/}} +{{- define "newrelic-logging.lowDataMode" -}} +{{/* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{/* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic-logging.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{/* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Returns logsEndpoint +*/}} +{{- define "newrelic-logging.logsEndpoint" -}} +{{- if (include "newrelic.nrStaging" .) -}} +https://staging-log-api.newrelic.com/log/v1 +{{- else if .Values.endpoint -}} +{{ .Values.endpoint -}} +{{- else if eq (substr 0 2 (include "newrelic-logging.licenseKey" .)) "eu" -}} +https://log-api.eu.newrelic.com/log/v1 +{{- else -}} +https://log-api.newrelic.com/log/v1 +{{- end -}} +{{- end -}} + +{{/* +Returns metricsHost +*/}} +{{- define "newrelic-logging.metricsHost" -}} +{{- if (include "newrelic.nrStaging" .) -}} +staging-metric-api.newrelic.com +{{- else if eq (substr 0 2 (include "newrelic-logging.licenseKey" .)) "eu" -}} +metric-api.eu.newrelic.com +{{- else -}} +metric-api.newrelic.com +{{- end -}} +{{- end -}} + +{{/* +Returns if the template should render, it checks if the required values are set. +*/}} +{{- define "newrelic-logging.areValuesValid" -}} +{{- $licenseKey := include "newrelic-logging.licenseKey" . -}} +{{- $customSecretName := include "newrelic-logging.customSecretName" . -}} +{{- $customSecretKey := include "newrelic-logging.customSecretKey" . -}} +{{- and (or $licenseKey (and $customSecretName $customSecretKey))}} +{{- end -}} + +{{/* +If additionalEnvVariables is set, renames to extraEnv. Returns extraEnv. +*/}} +{{- define "newrelic-logging.extraEnv" -}} +{{- if .Values.fluentBit }} + {{- if .Values.fluentBit.additionalEnvVariables }} + {{- toYaml .Values.fluentBit.additionalEnvVariables -}} + {{- else if .Values.fluentBit.extraEnv }} + {{- toYaml .Values.fluentBit.extraEnv -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/clusterrole.yaml new file mode 100644 index 000000000..b36340fe6 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/clusterrole.yaml @@ -0,0 +1,23 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: {{ include "newrelic-logging.labels" . | indent 4 }} + name: {{ template "newrelic-logging.fullname" . }} +rules: + - apiGroups: [""] + resources: + - namespaces + - pods + verbs: ["get", "list", "watch"] +{{- if .Values.rbac.pspEnabled }} + - apiGroups: + - extensions + resources: + - podsecuritypolicies + resourceNames: + - privileged-{{ template "newrelic-logging.fullname" . }} + verbs: + - use +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..6b258f697 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/clusterrolebinding.yaml @@ -0,0 +1,15 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: {{ include "newrelic-logging.labels" . | indent 4 }} + name: {{ template "newrelic-logging.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "newrelic-logging.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/configmap.yaml new file mode 100644 index 000000000..4b1d89014 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/configmap.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + labels: {{ include "newrelic-logging.labels" . | indent 4 }} + name: {{ template "newrelic-logging.fluentBitConfig" . }} +data: + fluent-bit.conf: | + {{- if .Values.fluentBit.config.service }} + {{- .Values.fluentBit.config.service | nindent 4 }} + {{- end }} + {{- if .Values.fluentBit.config.inputs }} + {{- .Values.fluentBit.config.inputs | nindent 4 }} + {{- end }} + {{- if .Values.fluentBit.config.extraInputs }} + {{- .Values.fluentBit.config.extraInputs | nindent 4}} + {{- end }} + {{- if and (include "newrelic-logging.lowDataMode" .) (.Values.fluentBit.config.lowDataModeFilters) }} + {{- .Values.fluentBit.config.lowDataModeFilters | nindent 4 }} + {{- else }} + {{- .Values.fluentBit.config.filters | nindent 4 }} + {{- end }} + {{- if .Values.fluentBit.config.extraFilters }} + {{- .Values.fluentBit.config.extraFilters | nindent 4}} + {{- end }} + {{- if .Values.fluentBit.config.outputs }} + {{- .Values.fluentBit.config.outputs | nindent 4 }} + {{- end }} + {{- if .Values.fluentBit.config.extraOutputs }} + {{- .Values.fluentBit.config.extraOutputs | nindent 4}} + {{- end }} + {{- if and (.Values.fluentBit.sendMetrics) (.Values.fluentBit.config.metricInstrumentation) }} + {{- .Values.fluentBit.config.metricInstrumentation | nindent 4}} + {{- end }} + parsers.conf: | + {{- if .Values.fluentBit.config.parsers }} + {{- .Values.fluentBit.config.parsers | nindent 4}} + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/daemonset-windows.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/daemonset-windows.yaml new file mode 100644 index 000000000..a4a9e08fc --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/daemonset-windows.yaml @@ -0,0 +1,171 @@ +{{- if and (include "newrelic-logging.areValuesValid" $) $.Values.enableWindows }} +{{- range .Values.windowsOsList }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + namespace: {{ $.Release.Namespace }} + labels: + kubernetes.io/os: windows +{{ include "newrelic-logging.labels" $ | indent 4 }} + name: {{ template "newrelic-logging.fullname" $ }}-windows-{{ .version }} + annotations: + {{- if $.Values.daemonSet.annotations }} +{{ toYaml $.Values.daemonSet.annotations | indent 4 }} + {{- end }} +spec: + updateStrategy: + type: {{ $.Values.updateStrategy }} + selector: + matchLabels: + app: {{ template "newrelic-logging.name" $ }} + release: {{ $.Release.Name }} + kubernetes.io/os: windows + template: + metadata: + annotations: + checksum/fluent-bit-config: {{ include (print $.Template.BasePath "/configmap.yaml") $ | sha256sum }} + {{- if $.Values.podAnnotations }} +{{ toYaml $.Values.podAnnotations | indent 8}} + {{- end }} + labels: + app: {{ template "newrelic-logging.name" $ }} + release: {{ $.Release.Name }} + kubernetes.io/os: windows + app.kubernetes.io/name: {{ template "newrelic-logging.name" $ }} + {{- if $.Values.podLabels}} +{{ toYaml $.Values.podLabels | indent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "newrelic.common.serviceAccount.name" $ }} + {{- with include "newrelic.common.dnsConfig" $ }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + dnsPolicy: ClusterFirst + terminationGracePeriodSeconds: 10 + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list $.Values.image.pullSecrets) "context" $) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + {{- if $.Values.windows.initContainers }} + initContainers: +{{ toYaml $.Values.windows.initContainers | indent 8 }} + {{- end }} + containers: + - name: {{ template "newrelic-logging.name" $ }} + # We have to use 'replace' to remove the double-quotes that "newrelic.common.images.image" has, so that + # we can append the Windows image tag suffix (and then re-quote that value) + image: "{{ include "newrelic.common.images.image" ( dict "imageRoot" $.Values.image "context" $) | replace "\"" ""}}-{{ .imageTagSuffix }}" + imagePullPolicy: "{{ $.Values.image.pullPolicy }}" + securityContext: {} + env: + - name: ENDPOINT + value: {{ include "newrelic-logging.logsEndpoint" $ | quote }} + - name: SOURCE + value: {{ if (include "newrelic-logging.lowDataMode" $) }} "k8s" {{- else }} "kubernetes" {{- end }} + - name: LICENSE_KEY + valueFrom: + secretKeyRef: + {{- if (include "newrelic-logging.licenseKey" $) }} + name: {{ template "newrelic-logging.fullname" $ }}-config + key: license + {{- else }} + name: {{ include "newrelic-logging.customSecretName" $ }} + key: {{ include "newrelic-logging.customSecretKey" $ }} + {{- end }} + - name: CLUSTER_NAME + value: {{ include "newrelic-logging.cluster" $ }} + - name: LOG_LEVEL + value: {{ $.Values.fluentBit.logLevel | quote }} + - name: LOG_PARSER + {{- if $.Values.fluentBit.criEnabled }} + value: "cri,docker" + {{- else }} + value: "docker,cri" + {{- end }} + {{- if or (not $.Values.fluentBit.persistence) (eq $.Values.fluentBit.persistence.mode "hostPath") }} + - name: FB_DB + value: {{ $.Values.fluentBit.windowsDb | quote }} + {{- else }} + - name: FB_DB + value: "" + {{- end }} + - name: PATH + value: {{ $.Values.fluentBit.windowsPath | quote }} + - name: K8S_BUFFER_SIZE + value: {{ $.Values.fluentBit.k8sBufferSize | quote }} + - name: K8S_LOGGING_EXCLUDE + value: {{ $.Values.fluentBit.k8sLoggingExclude | default "false" | quote }} + - name: LOW_DATA_MODE + value: {{ include "newrelic-logging.lowDataMode" $ | default "false" | quote }} + - name: RETRY_LIMIT + value: {{ $.Values.fluentBit.retryLimit | quote }} + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SEND_OUTPUT_PLUGIN_METRICS + value: {{ $.Values.fluentBit.sendMetrics | default "false" | quote }} + - name: METRICS_HOST + value: {{ include "newrelic-logging.metricsHost" $ | quote }} + {{- include "newrelic-logging.extraEnv" $ | nindent 12 }} + command: + - C:\fluent-bit\bin\fluent-bit.exe + - -c + - c:\fluent-bit\etc\fluent-bit.conf + - -e + - C:\fluent-bit\bin\out_newrelic.dll + {{- if $.Values.exposedPorts }} + ports: {{ toYaml $.Values.exposedPorts | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: C:\fluent-bit\etc + name: fluent-bit-config + - mountPath: C:\var\log + name: logs + {{- if and ($.Values.fluentBit.persistence) (ne $.Values.fluentBit.persistence.mode "hostPath") }} + readOnly: true + {{- end }} + # We need to also mount this because the logs in C:\var\logs are actually symlinks to C:\ProgramData. + # So, in order to be able to read these logs, the reading process needs to also have access to C:\ProgramData. + - mountPath: C:\ProgramData + name: progdata + {{- if and ($.Values.fluentBit.persistence) (ne $.Values.fluentBit.persistence.mode "hostPath") }} + readOnly: true + {{- end }} + {{- if $.Values.resources }} + resources: +{{ toYaml $.Values.resources | indent 12 }} + {{- end }} + volumes: + - name: fluent-bit-config + configMap: + name: {{ template "newrelic-logging.fluentBitConfig" $ }} + - name: logs + hostPath: + path: C:\var\log + - name: progdata + hostPath: + path: C:\ProgramData + {{- if $.Values.priorityClassName }} + priorityClassName: {{ $.Values.priorityClassName }} + {{- end }} + nodeSelector: + {{- if $.Values.windowsNodeSelector }} +{{ toYaml $.Values.windowsNodeSelector | indent 8 }} + {{- else }} + kubernetes.io/os: windows + # Windows containers can only be executed on hosts running the exact same Windows version and build number + node.kubernetes.io/windows-build: {{ .buildNumber }} + {{- end }} + {{- if $.Values.tolerations }} + tolerations: +{{ toYaml $.Values.tolerations | indent 8 }} + {{- end }} +--- +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/daemonset.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/daemonset.yaml new file mode 100644 index 000000000..1bc779a99 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/daemonset.yaml @@ -0,0 +1,208 @@ +{{- if and (include "newrelic-logging.areValuesValid" .) .Values.enableLinux }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + namespace: {{ .Release.Namespace }} + labels: {{ include "newrelic-logging.labels" . | indent 4 }} + name: {{ template "newrelic-logging.fullname" . }} + annotations: + {{- if .Values.daemonSet.annotations }} +{{ toYaml .Values.daemonSet.annotations | indent 4 }} + {{- end }} +spec: + updateStrategy: + type: {{ .Values.updateStrategy }} + selector: + matchLabels: + app: {{ template "newrelic-logging.name" . }} + release: {{.Release.Name }} + template: + metadata: + annotations: + checksum/fluent-bit-config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | indent 8}} + {{- end }} + labels: + app: {{ template "newrelic-logging.name" . }} + release: {{.Release.Name }} + kubernetes.io/os: linux + app.kubernetes.io/name: {{ template "newrelic-logging.name" . }} + {{- if .Values.podLabels}} +{{ toYaml .Values.podLabels | indent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + dnsPolicy: ClusterFirstWithHostNet + terminationGracePeriodSeconds: 10 + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.image.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + initContainers: + {{- if and (.Values.fluentBit.persistence) (eq .Values.fluentBit.persistence.mode "persistentVolume") }} + - name: init + image: busybox:1.36 + command: ["/bin/sh", "-c"] + args: ["/bin/find /db -type f -mtime +1 -delete"] # Delete all db files not updated in the last 24h + volumeMounts: + - name: fb-db-pvc + mountPath: /db + {{- end }} + {{- if .Values.initContainers }} +{{ toYaml .Values.initContainers | indent 8 }} + {{- end }} + containers: + - name: {{ template "newrelic-logging.name" . }} + {{- with include "newrelic.common.securityContext.container" . }} + securityContext: + {{- . | nindent 12 }} + {{- end }} + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.image "context" .) }} + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + env: + - name: ENDPOINT + value: {{ include "newrelic-logging.logsEndpoint" . | quote }} + - name: SOURCE + value: {{ if (include "newrelic-logging.lowDataMode" .) }} "k8s" {{- else }} "kubernetes" {{- end }} + - name: LICENSE_KEY + valueFrom: + secretKeyRef: + {{- if (include "newrelic-logging.licenseKey" .) }} + name: {{ template "newrelic-logging.fullname" . }}-config + key: license + {{- else }} + name: {{ include "newrelic-logging.customSecretName" . }} + key: {{ include "newrelic-logging.customSecretKey" . }} + {{- end }} + - name: CLUSTER_NAME + value: {{ include "newrelic-logging.cluster" . }} + - name: LOG_LEVEL + value: {{ .Values.fluentBit.logLevel | quote }} + - name: LOG_PARSER + {{- if .Values.fluentBit.criEnabled }} + value: "cri,docker" + {{- else }} + value: "docker,cri" + {{- end }} + {{- if or (not .Values.fluentBit.persistence) (eq .Values.fluentBit.persistence.mode "hostPath") }} + - name: FB_DB + value: {{ .Values.fluentBit.db | quote }} + {{- else if eq .Values.fluentBit.persistence.mode "persistentVolume" }} + - name: FB_DB + value: "/db/$(NODE_NAME)-fb.db" + {{- else }} + - name: FB_DB + value: "" + {{- end }} + - name: PATH + value: {{ .Values.fluentBit.path | quote }} + - name: K8S_BUFFER_SIZE + value: {{ .Values.fluentBit.k8sBufferSize | quote }} + - name: K8S_LOGGING_EXCLUDE + value: {{ .Values.fluentBit.k8sLoggingExclude | default "false" | quote }} + - name: LOW_DATA_MODE + value: {{ include "newrelic-logging.lowDataMode" . | default "false" | quote }} + - name: RETRY_LIMIT + value: {{ .Values.fluentBit.retryLimit | quote }} + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SEND_OUTPUT_PLUGIN_METRICS + value: {{ $.Values.fluentBit.sendMetrics | default "false" | quote }} + - name: METRICS_HOST + value: {{ include "newrelic-logging.metricsHost" . | quote }} + {{- include "newrelic-logging.extraEnv" . | nindent 12 }} + command: + - /fluent-bit/bin/fluent-bit + - -c + - /fluent-bit/etc/fluent-bit.conf + - -e + - /fluent-bit/bin/out_newrelic.so + volumeMounts: + - name: fluent-bit-config + mountPath: /fluent-bit/etc + - name: logs + # We mount /var by default because container logs could be on /var/log or /var/lib/docker/containers (symlinked to /var/log) + mountPath: {{ .Values.fluentBit.linuxMountPath | default "/var" }} + {{- if and (.Values.fluentBit.persistence) (ne .Values.fluentBit.persistence.mode "hostPath") }} + readOnly: true + {{- end }} + {{- if and (.Values.fluentBit.persistence) (eq .Values.fluentBit.persistence.mode "persistentVolume") }} + - name: fb-db-pvc + mountPath: /db + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + {{- if .Values.exposedPorts }} + ports: {{ toYaml .Values.exposedPorts | nindent 12 }} + {{- end }} + {{- if .Values.resources }} + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- end }} + volumes: + - name: fluent-bit-config + configMap: + name: {{ template "newrelic-logging.fluentBitConfig" . }} + - name: logs + hostPath: + path: {{ .Values.fluentBit.linuxMountPath | default "/var" }} + {{- if and (.Values.fluentBit.persistence) (eq .Values.fluentBit.persistence.mode "persistentVolume") }} + - name: fb-db-pvc + persistentVolumeClaim: + {{- if .Values.fluentBit.persistence.persistentVolume.existingVolumeClaim }} + claimName: {{ .Values.fluentBit.persistence.persistentVolume.existingVolumeClaim }} + {{- else }} + claimName: {{ template "newrelic-logging.fullname" . }}-pvc + {{- end }} + {{- end }} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} + {{- if $.Values.priorityClassName }} + priorityClassName: {{ $.Values.priorityClassName }} + {{- end }} + {{- if .Values.nodeAffinity }} + affinity: + nodeAffinity: {{ .Values.nodeAffinity | toYaml | nindent 10 }} + {{- else if include "newrelic.fargate" . }} + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: eks.amazonaws.com/compute-type + operator: NotIn + values: + - fargate + {{- end }} + nodeSelector: + {{- if .Values.nodeSelector }} +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- else if $.Values.enableWindows }} + # We add this only if Windows is enabled to keep backwards-compatibility. Prior to version 1.14, this label was + # named beta.kubernetes.io/os. In version 1.14, it was deprecated and replaced by this one. Version 1.14 also + # introduces Windows support. Therefore, anyone wishing to use Windows containers must bet at version >=1.14 and + # are going to need this label, in order to avoid placing a linux container on a windows node, and vice-versa. + kubernetes.io/os: linux + {{- end }} + {{- if .Values.tolerations }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/persistentvolume.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/persistentvolume.yaml new file mode 100644 index 000000000..f2fb93d77 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/persistentvolume.yaml @@ -0,0 +1,57 @@ +{{- if (not (empty .Values.fluentBit.persistence)) }} + +{{- if and (eq .Values.fluentBit.persistence.mode "persistentVolume") (not .Values.fluentBit.persistence.persistentVolume.storageClass) (not .Values.fluentBit.persistence.persistentVolume.existingVolumeClaim) }} +{{ fail "You should provide a ReadWriteMany storageClass or an existingVolumeClaim if using persitentVolume as Fluent Bit persistence mode." }} +{{- end }} + +{{- if and (eq .Values.fluentBit.persistence.mode "persistentVolume") (not .Values.fluentBit.persistence.persistentVolume.existingVolumeClaim) }} +{{- if and (not .Values.fluentBit.persistence.persistentVolume.dynamicProvisioning) (not .Values.fluentBit.persistence.persistentVolume.existingVolume) }} +apiVersion: v1 +kind: PersistentVolume +metadata: + namespace: {{ .Release.Namespace }} + labels: {{ include "newrelic-logging.labels" . | indent 4 }} + name: {{ template "newrelic-logging.fullname" . }}-pv + annotations: + {{- if .Values.fluentBit.persistence.persistentVolume.annotations.volume }} +{{ toYaml .Values.fluentBit.persistence.persistentVolume.annotations.volume | indent 4 }} + {{- end }} +spec: + accessModes: + - ReadWriteMany + capacity: + storage: {{ .Values.fluentBit.persistence.persistentVolume.size }} + storageClassName: {{ .Values.fluentBit.persistence.persistentVolume.storageClass }} + persistentVolumeReclaimPolicy: Delete + {{- if .Values.fluentBit.persistence.persistentVolume.extra.volume }} +{{ toYaml .Values.fluentBit.persistence.persistentVolume.extra.volume | indent 2 }} + {{- end }} +--- +{{- end }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + namespace: {{ .Release.Namespace }} + labels: {{ include "newrelic-logging.labels" . | indent 4 }} + name: {{ template "newrelic-logging.fullname" . }}-pvc + annotations: + {{- if .Values.fluentBit.persistence.persistentVolume.annotations.claim }} +{{ toYaml .Values.fluentBit.persistence.persistentVolume.annotations.claim | indent 4 }} + {{- end }} +spec: + storageClassName: {{ .Values.fluentBit.persistence.persistentVolume.storageClass }} + accessModes: + - ReadWriteMany +{{- if .Values.fluentBit.persistence.persistentVolume.existingVolume }} + volumeName: {{ .Values.fluentBit.persistence.persistentVolume.existingVolume }} +{{- else if not .Values.fluentBit.persistence.persistentVolume.dynamicProvisioning }} + volumeName: {{ template "newrelic-logging.fullname" . }}-pv +{{- end }} + resources: + requests: + storage: {{ .Values.fluentBit.persistence.persistentVolume.size }} + {{- if .Values.fluentBit.persistence.persistentVolume.extra.claim }} +{{ toYaml .Values.fluentBit.persistence.persistentVolume.extra.claim | indent 2 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/podsecuritypolicy.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..2c8c598e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/podsecuritypolicy.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.pspEnabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: privileged-{{ template "newrelic-logging.fullname" . }} +spec: + allowedCapabilities: + - '*' + fsGroup: + rule: RunAsAny + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - '*' + hostPID: true + hostIPC: true + hostPorts: + - min: 1 + max: 65536 +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/secret.yaml new file mode 100644 index 000000000..47a56e573 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/secret.yaml @@ -0,0 +1,12 @@ +{{- $licenseKey := include "newrelic-logging.licenseKey" . -}} +{{- if $licenseKey }} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + labels: {{ include "newrelic-logging.labels" . | indent 4 }} + name: {{ template "newrelic-logging.fullname" . }}-config +type: Opaque +data: + license: {{ $licenseKey | b64enc }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/serviceaccount.yaml new file mode 100644 index 000000000..51da56a3e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- if include "newrelic.common.serviceAccount.annotations" . }} + annotations: + {{- include "newrelic.common.serviceAccount.annotations" . | nindent 4 }} + {{- end }} + labels: + app: {{ template "newrelic-logging.name" . }} + chart: {{ template "newrelic-logging.chart" . }} + heritage: "{{ .Release.Service }}" + release: "{{ .Release.Name }}" + {{- /*include "newrelic.common.labels" . | nindent 4 /!\ Breaking change /!\ */}} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/cri_parser_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/cri_parser_test.yaml new file mode 100644 index 000000000..f4a1d01d0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/cri_parser_test.yaml @@ -0,0 +1,37 @@ +suite: test cri, docker parser options in daemonsets +templates: + - templates/configmap.yaml + - templates/daemonset.yaml + - templates/daemonset-windows.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: cri enabled by default and docker as fallback + templates: + - templates/daemonset.yaml + - templates/daemonset-windows.yaml + set: + licenseKey: nr_license_key + enableWindows: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOG_PARSER + value: "cri,docker" + - it: docker is set if enabled by and cri as fallback + templates: + - templates/daemonset.yaml + - templates/daemonset-windows.yaml + set: + licenseKey: nr_license_key + enableWindows: true + fluentBit: + criEnabled: false + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOG_PARSER + value: "docker,cri" \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/dns_config_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/dns_config_test.yaml new file mode 100644 index 000000000..76d24eac5 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/dns_config_test.yaml @@ -0,0 +1,62 @@ +suite: test dnsConfig options in daemonsets +templates: + - templates/configmap.yaml + - templates/daemonset.yaml + - templates/daemonset-windows.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: daemonsets contain dnsConfig block when provided + set: + licenseKey: nr_license_key + enableWindows: true + dnsConfig: + nameservers: + - 192.0.2.1 + asserts: + - exists: + path: spec.template.spec.dnsConfig + template: templates/daemonset.yaml + - exists: + path: spec.template.spec.dnsConfig + template: templates/daemonset-windows.yaml + + - it: daemonsets do not contain dnsConfig block when not provided + set: + licenseKey: nr_license_key + enableWindows: true + dnsConfig: {} + asserts: + - notExists: + path: spec.template.spec.dnsConfig + template: templates/daemonset.yaml + - notExists: + path: spec.template.spec.dnsConfig + template: templates/daemonset-windows.yaml + + - it: daemonsets contain provided dnsConfig options + set: + licenseKey: nr_license_key + enableWindows: true + dnsConfig: + options: + - name: ndots + value: "1" + asserts: + - equal: + path: spec.template.spec.dnsConfig.options[0].name + value: ndots + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.dnsConfig.options[0].value + value: "1" + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.dnsConfig.options[0].name + value: ndots + template: templates/daemonset-windows.yaml + - equal: + path: spec.template.spec.dnsConfig.options[0].value + value: "1" + template: templates/daemonset-windows.yaml diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/endpoint_region_selection_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/endpoint_region_selection_test.yaml new file mode 100644 index 000000000..82e700d93 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/endpoint_region_selection_test.yaml @@ -0,0 +1,128 @@ +suite: test endpoint selection based on region settings +templates: + - templates/configmap.yaml + - templates/daemonset.yaml + - templates/daemonset-windows.yaml +release: + name: endpoint-selection-release + namespace: endpoint-selection-namespace +tests: + + - it: selects staging endpoints if nrStaging is enabled + set: + licenseKey: nr_license_key + nrStaging: true + enableWindows: true + asserts: + # Linux + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: "https://staging-log-api.newrelic.com/log/v1" + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: METRICS_HOST + value: "staging-metric-api.newrelic.com" + template: templates/daemonset.yaml + # Windows + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: "https://staging-log-api.newrelic.com/log/v1" + template: templates/daemonset-windows.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: METRICS_HOST + value: "staging-metric-api.newrelic.com" + template: templates/daemonset-windows.yaml + + - it: selects US endpoints for a US license key + set: + licenseKey: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaFFFFNRAL + enableWindows: true + asserts: + # Linux + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: "https://log-api.newrelic.com/log/v1" + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: METRICS_HOST + value: "metric-api.newrelic.com" + template: templates/daemonset.yaml + # Windows + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: "https://log-api.newrelic.com/log/v1" + template: templates/daemonset-windows.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: METRICS_HOST + value: "metric-api.newrelic.com" + template: templates/daemonset-windows.yaml + + - it: selects EU endpoints for a EU license key + set: + licenseKey: euaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaFFFFNRAL + enableWindows: true + asserts: + # Linux + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: "https://log-api.eu.newrelic.com/log/v1" + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: METRICS_HOST + value: "metric-api.eu.newrelic.com" + template: templates/daemonset.yaml + # Windows + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: "https://log-api.eu.newrelic.com/log/v1" + template: templates/daemonset-windows.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: METRICS_HOST + value: "metric-api.eu.newrelic.com" + template: templates/daemonset-windows.yaml + + + - it: selects custom logs endpoint if provided + set: + licenseKey: euaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaFFFFNRAL + endpoint: custom + enableWindows: true + asserts: + # Linux + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: "custom" + template: templates/daemonset.yaml + # Windows + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: "custom" + template: templates/daemonset-windows.yaml \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_k8logging_exclude_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_k8logging_exclude_test.yaml new file mode 100644 index 000000000..446f829b0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_k8logging_exclude_test.yaml @@ -0,0 +1,45 @@ +suite: test fluent-bit exclude logging +templates: + - templates/daemonset.yaml + - templates/configmap.yaml + - templates/persistentvolume.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: K8S_LOGGING_EXCLUDE set true + templates: + - templates/daemonset.yaml + set: + licenseKey: nr_license_key + fluentBit: + k8sLoggingExclude: true + asserts: + - equal: + path: spec.template.spec.containers[0].env[?(@.name=="K8S_LOGGING_EXCLUDE")].value + value: "true" + template: templates/daemonset.yaml + - it: K8S_LOGGING_EXCLUDE set false + templates: + - templates/daemonset.yaml + set: + licenseKey: nr_license_key + fluentBit: + k8sLoggingExclude: false + asserts: + - equal: + path: spec.template.spec.containers[0].env[?(@.name=="K8S_LOGGING_EXCLUDE")].value + value: "false" + template: templates/daemonset.yaml + - it: K8S_LOGGING_EXCLUDE set value xyz and expect it to be set + templates: + - templates/daemonset.yaml + set: + licenseKey: nr_license_key + fluentBit: + k8sLoggingExclude: xyz + asserts: + - equal: + path: spec.template.spec.containers[0].env[?(@.name=="K8S_LOGGING_EXCLUDE")].value + value: "xyz" + template: templates/daemonset.yaml diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_persistence_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_persistence_test.yaml new file mode 100644 index 000000000..67d14c795 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_persistence_test.yaml @@ -0,0 +1,317 @@ +suite: test fluent-bit persistence options +templates: + - templates/daemonset.yaml + - templates/configmap.yaml + - templates/persistentvolume.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: default persistence is hostPath, DB is set properly and logs volume is read/write + set: + licenseKey: nr_license_key + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: logs + mountPath: /var + template: templates/daemonset.yaml + - notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: fb-db-pvc + mountPath: /db + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.volumes + content: + name: logs + hostPath: + path: /var + template: templates/daemonset.yaml + - notContains: + path: spec.template.spec.volumes + content: + name: fb-db-pvc + persistentVolumeClaim: + claimName: my-release-newrelic-logging-pvc + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: FB_DB + value: /var/log/flb_kube.db + template: templates/daemonset.yaml + - hasDocuments: + count: 0 + template: templates/persistentvolume.yaml + - it: fluentBit.persistence set to none should keep FB_DB env empty and mount logs volume as read-only + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: none + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: FB_DB + value: "" + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: logs + mountPath: /var + readOnly: true + template: templates/daemonset.yaml + - notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: fb-db-pvc + mountPath: /db + template: templates/daemonset.yaml + - notContains: + path: spec.template.spec.volumes + content: + name: fb-db-pvc + persistentVolumeClaim: + claimName: my-release-newrelic-logging-pvc + template: templates/daemonset.yaml + - hasDocuments: + count: 0 + template: templates/persistentvolume.yaml + - it: fluentBit.persistence set to persistentVolume should create volume, add it to daemonset, add an initContainer to cleanup and set the FB_DB. Dynamic provisioning is enabled by default. + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: FB_DB + value: "/db/$(NODE_NAME)-fb.db" + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: logs + mountPath: /var + readOnly: true + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: fb-db-pvc + mountPath: /db + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.volumes + content: + name: fb-db-pvc + persistentVolumeClaim: + claimName: my-release-newrelic-logging-pvc + template: templates/daemonset.yaml + - isNotNullOrEmpty: + path: spec.template.spec.initContainers + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.initContainers[0].volumeMounts + content: + name: fb-db-pvc + mountPath: /db + template: templates/daemonset.yaml + - hasDocuments: + count: 1 + template: templates/persistentvolume.yaml + - isKind: + of: PersistentVolumeClaim + template: templates/persistentvolume.yaml + - equal: + path: spec.accessModes + value: + - ReadWriteMany + template: templates/persistentvolume.yaml + - it: fluentBit.persistence.persistentVolume with non dynamic provisioning should create the PV and PVC + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + dynamicProvisioning: false + asserts: + - hasDocuments: + count: 2 + template: templates/persistentvolume.yaml + - isKind: + of: PersistentVolume + documentIndex: 0 + template: templates/persistentvolume.yaml + - isKind: + of: PersistentVolumeClaim + documentIndex: 1 + template: templates/persistentvolume.yaml + - equal: + path: spec.accessModes + value: + - ReadWriteMany + documentIndex: 0 + template: templates/persistentvolume.yaml + - equal: + path: spec.accessModes + value: + - ReadWriteMany + documentIndex: 1 + template: templates/persistentvolume.yaml + - it: fluentBit.persistence storage class should be set properly on PV and PVC + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + dynamicProvisioning: false + storageClass: sample-storage-rwx + asserts: + - equal: + path: spec.storageClassName + value: sample-storage-rwx + documentIndex: 0 + template: templates/persistentvolume.yaml + - equal: + path: spec.storageClassName + value: sample-storage-rwx + documentIndex: 1 + template: templates/persistentvolume.yaml + - it: fluentBit.persistence.persistentVolume size should be set properly on PV and PVC + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + dynamicProvisioning: false + size: 100Gi + asserts: + - equal: + path: spec.capacity.storage + value: 100Gi + documentIndex: 0 + template: templates/persistentvolume.yaml + - equal: + path: spec.resources.requests.storage + value: 100Gi + documentIndex: 1 + template: templates/persistentvolume.yaml + - it: fluentBit.persistence.persistentVolume not dynamic provisioned but volumeName provided should use the volumeName and do not create a PV + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + dynamicProvisioning: false + existingVolume: existing-volume + asserts: + - hasDocuments: + count: 1 + template: templates/persistentvolume.yaml + - isKind: + of: PersistentVolumeClaim + template: templates/persistentvolume.yaml + - equal: + path: spec.volumeName + value: existing-volume + template: templates/persistentvolume.yaml + - it: fluentBit.persistence.persistentVolume if a existing claim is provided it's used and PV/PVC are not created + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + dynamicProvisioning: false + existingVolumeClaim: existing-claim + asserts: + - hasDocuments: + count: 0 + template: templates/persistentvolume.yaml + - contains: + path: spec.template.spec.volumes + content: + name: fb-db-pvc + persistentVolumeClaim: + claimName: existing-claim + template: templates/daemonset.yaml + - it: fluentBit.persistence.persistentVolume annotations for PV and PVC are used + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + annotations: + volume: + foo: bar + claim: + baz: qux + dynamicProvisioning: false + asserts: + - equal: + path: metadata.annotations.foo + value: bar + documentIndex: 0 + template: templates/persistentvolume.yaml + - equal: + path: metadata.annotations.baz + value: qux + documentIndex: 1 + template: templates/persistentvolume.yaml + - it: fluentBit.persistence.persistentVolume extra for PV and PVC are used + set: + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + extra: + volume: + nfs: + path: /tmp/ + server: 1.1.1.1 + claim: + some: property + dynamicProvisioning: false + asserts: + - equal: + path: spec.nfs + value: + path: /tmp/ + server: 1.1.1.1 + documentIndex: 0 + template: templates/persistentvolume.yaml + - equal: + path: spec.some + value: property + documentIndex: 1 + template: templates/persistentvolume.yaml diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_pod_label_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_pod_label_test.yaml new file mode 100644 index 000000000..86edd7ccd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_pod_label_test.yaml @@ -0,0 +1,48 @@ +suite: test fluent-bit pods labels +templates: + - templates/daemonset.yaml + - templates/configmap.yaml + - templates/persistentvolume.yaml +release: + name: my-release + namespace: my-namespace +tests: +- it: multiple pod labels are set properly + templates: + - templates/daemonset.yaml + set: + licenseKey: nr_license_key + podLabels: + key1: value1 + key2: value2 + asserts: + - equal: + path: spec.template.metadata.labels.key1 + value: value1 + template: templates/daemonset.yaml + - equal: + path: spec.template.metadata.labels.key2 + value: value2 + template: templates/daemonset.yaml +- it: single pod label set properly + templates: + - templates/daemonset.yaml + set: + licenseKey: nr_license_key + podLabels: + key1: value1 + asserts: + - equal: + path: spec.template.metadata.labels.key1 + value: value1 + template: templates/daemonset.yaml +- it: pod labels are not set + templates: + - templates/daemonset.yaml + set: + licenseKey: nr_license_key + asserts: + - notExists: + path: spec.template.metadata.labels.key1 + - notExists: + path: spec.template.metadata.labels.key2 \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_sendmetrics_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_sendmetrics_test.yaml new file mode 100644 index 000000000..f320172cb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/fluentbit_sendmetrics_test.yaml @@ -0,0 +1,74 @@ +suite: test fluentbit send metrics +templates: + - templates/configmap.yaml + - templates/daemonset.yaml + - templates/daemonset-windows.yaml +release: + name: sendmetrics-release + namespace: sendmetrics-namespace +tests: + + - it: sets requirement environment variables to send metrics + set: + licenseKey: nr_license_key + enableWindows: true + fluentBit.sendMetrics: true + asserts: + # Linux + - contains: + path: spec.template.spec.containers[0].env + content: + name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: SEND_OUTPUT_PLUGIN_METRICS + value: "true" + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: METRICS_HOST + value: "metric-api.newrelic.com" + template: templates/daemonset.yaml + # Windows + - contains: + path: spec.template.spec.containers[0].env + content: + name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + template: templates/daemonset-windows.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + template: templates/daemonset-windows.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: SEND_OUTPUT_PLUGIN_METRICS + value: "true" + template: templates/daemonset-windows.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: METRICS_HOST + value: "metric-api.newrelic.com" + template: templates/daemonset-windows.yaml diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/images_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/images_test.yaml new file mode 100644 index 000000000..3dc5b7a4e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/images_test.yaml @@ -0,0 +1,96 @@ +suite: test images settings +templates: + - templates/configmap.yaml + - templates/daemonset.yaml + - templates/daemonset-windows.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: image names are correct + templates: + - templates/daemonset.yaml + - templates/daemonset-windows.yaml + set: + licenseKey: nr_license_key + enableWindows: true + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: newrelic/newrelic-fluentbit-output:2.0.0 + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.containers[0].image + value: newrelic/newrelic-fluentbit-output:2.0.0-windows-ltsc-2019 + template: templates/daemonset-windows.yaml + documentIndex: 0 + - equal: + path: spec.template.spec.containers[0].image + value: newrelic/newrelic-fluentbit-output:2.0.0-windows-ltsc-2022 + template: templates/daemonset-windows.yaml + documentIndex: 1 + - it: global registry is used if set + templates: + - templates/daemonset.yaml + - templates/daemonset-windows.yaml + set: + licenseKey: nr_license_key + enableWindows: true + global: + images: + registry: global_registry + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: global_registry/.* + - it: local registry overrides global + templates: + - templates/daemonset.yaml + - templates/daemonset-windows.yaml + set: + licenseKey: nr_license_key + enableWindows: true + global: + images: + registry: global_registry + image: + registry: local_registry + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: local_registry/.* + - it: pullSecrets is used if defined + templates: + - templates/daemonset.yaml + - templates/daemonset-windows.yaml + set: + licenseKey: nr_license_key + enableWindows: true + image: + pullSecrets: + - name: regsecret + asserts: + - equal: + path: spec.template.spec.imagePullSecrets[0].name + value: regsecret + - it: pullSecrets are merged + templates: + - templates/daemonset.yaml + - templates/daemonset-windows.yaml + set: + licenseKey: nr_license_key + enableWindows: true + global: + images: + pullSecrets: + - name: global_regsecret + image: + pullSecrets: + - name: regsecret + asserts: + - equal: + path: spec.template.spec.imagePullSecrets[0].name + value: global_regsecret + - equal: + path: spec.template.spec.imagePullSecrets[1].name + value: regsecret diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/linux_volume_mount_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/linux_volume_mount_test.yaml new file mode 100644 index 000000000..83d2a2c11 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/linux_volume_mount_test.yaml @@ -0,0 +1,37 @@ +suite: test fluent-bit linux mount for logs +templates: + - templates/configmap.yaml + - templates/daemonset.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: is set to /var by default an + set: + licenseKey: nr_license_key + asserts: + - equal: + path: spec.template.spec.containers[0].volumeMounts[1].mountPath + value: /var + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.volumes[1].hostPath.path + value: /var + template: templates/daemonset.yaml + documentIndex: 0 + - it: is set to linuxMountPath if set + templates: + - templates/daemonset.yaml + set: + licenseKey: nr_license_key + fluentBit.linuxMountPath: /var/log + asserts: + - equal: + path: spec.template.spec.containers[0].volumeMounts[1].mountPath + value: /var/log + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.volumes[1].hostPath.path + value: /var/log + template: templates/daemonset.yaml + documentIndex: 0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/rbac_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/rbac_test.yaml new file mode 100644 index 000000000..a8d85da98 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/tests/rbac_test.yaml @@ -0,0 +1,48 @@ +suite: test RBAC creation +templates: + - templates/clusterrolebinding.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: template rbac if it is configured to do it + set: + rbac.create: true + asserts: + - hasDocuments: + count: 1 + + - it: don't template rbac if it is disabled + set: + rbac.create: false + asserts: + - hasDocuments: + count: 0 + + - it: RBAC points to the service account that is created by default + set: + rbac.create: true + serviceAccount.create: true + asserts: + - equal: + path: subjects[0].name + value: my-release-newrelic-logging + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + rbac.create: true + serviceAccount.create: false + serviceAccount.name: sa-test + asserts: + - equal: + path: subjects[0].name + value: sa-test + + - it: RBAC points to the default service account when serviceAccount is disabled + set: + rbac.create: true + serviceAccount.create: false + asserts: + - equal: + path: subjects[0].name + value: default diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/values.yaml new file mode 100644 index 000000000..991f9ee9c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-logging/values.yaml @@ -0,0 +1,357 @@ +# IMPORTANT: Specify your New Relic API key here. +# licenseKey: +# +# Optionally, specify a cluster name and log records can +# be filtered by cluster. +# cluster: +# +# or Specify secret which contains New Relic API key +# customSecretName: secret_name +# customSecretLicenseKey: secret_key +# +# The previous values can also be set as global so that they +# can be shared by other newrelic product's charts +# +# global: +# licenseKey: +# cluster: +# customSecretName: +# customSecretLicenseKey: +# +# IMPORTANT: if you use a kubernetes secret to specify the license, +# you have to manually provide the correct endpoint depending on +# whether your account is for the EU region or not. +# +# endpoint: https://log-api.newrelic.com/log/v1 + +fluentBit: + logLevel: "info" + path: "/var/log/containers/*.log" + linuxMountPath: /var + windowsPath: "C:\\var\\log\\containers\\*.log" + db: "/var/log/flb_kube.db" + windowsDb: "C:\\var\\log\\flb_kube.db" + criEnabled: true + k8sBufferSize: "32k" + k8sLoggingExclude: "false" + retryLimit: 5 + sendMetrics: false + extraEnv: [] + # extraEnv: + # - name: HTTPS_PROXY + # value: http://example.com:3128 + # - name: METADATA_NAME + # valueFrom: + # fieldRef: + # fieldPath: metadata.name + + # Indicates how fluent-bit database is persisted + persistence: + # Define the persistent mode for fluent-bit db, allowed options are `hostPath` (default), `none`, `persistentVolume`. + # - `hostPath` will use hostPath to store the db file on the node disk. + # - `none` will disable the fluent-bit db file, this could cause log duplication or data loss in case fluent-bit gets restarted. + # - `persistentVolume` will use a ReadWriteMany persistent volume to store the db file. This will override `fluentBit.db` path and use `/db/${NODE_NAME}-fb.db` file instead. + mode: "hostPath" + + # In case persistence.mode is set to persistentVolume this will be needed + persistentVolume: + # The storage class should allow ReadWriteMany mode + storageClass: + # Volume and claim size. + size: 10Gi + # If dynamicProvisioning is enabled the chart will create only the PersistentVolumeClaim + dynamicProvisioning: true + # If an existingVolume is provided, we'll use it instead creating a new one + existingVolume: + # If an existingVolumeClaim is provided, we'll use it instead creating a new one + existingVolumeClaim: + # In case you need to add annotations to the created volume or claim + annotations: + volume: {} + claim: {} + # In case you need to specify any other option to your volume or claim + extra: + volume: + # nfs: + # path: /tmp/ + # server: 1.1.1.1 + claim: {} + + + # New Relic default configuration for fluent-bit.conf (service, inputs, filters, outputs) + # and parsers.conf (parsers). The configuration below is not configured for lowDataMode and will + # send all attributes. If custom configuration is required, update these variables. + config: + # Note that Prometheus metric collection needs the HTTP server to be online at port 2020 (see fluentBit.config.metricInstrumentation) + service: | + [SERVICE] + Flush 1 + Log_Level ${LOG_LEVEL} + Daemon off + Parsers_File parsers.conf + HTTP_Server On + HTTP_Listen 0.0.0.0 + HTTP_Port 2020 + + inputs: | + [INPUT] + Name tail + Alias pod-logs-tailer + Tag kube.* + Path ${PATH} + multiline.parser ${LOG_PARSER} + DB ${FB_DB} + Mem_Buf_Limit 7MB + Skip_Long_Lines On + Refresh_Interval 10 + +# extraInputs: | +# [INPUT] +# Name dummy +# Tag dummy.log + + filters: | + [FILTER] + Name kubernetes + Alias kubernetes-enricher + Match kube.* + # We need the full DNS suffix as Windows only supports resolving names with this suffix + # See: https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/#dns-limitations + Kube_URL https://kubernetes.default.svc.cluster.local:443 + Buffer_Size ${K8S_BUFFER_SIZE} + K8S-Logging.Exclude ${K8S_LOGGING_EXCLUDE} + + [FILTER] + Name record_modifier + Alias node-attributes-enricher + Match * + Record cluster_name "${CLUSTER_NAME}" + +# extraFilters: | +# [FILTER] +# Name grep +# Match * +# Exclude log lvl=debug* + + lowDataModeFilters: | + [FILTER] + Name kubernetes + Match kube.* + Alias kubernetes-enricher + # We need the full DNS suffix as Windows only supports resolving names with this suffix + # See: https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/#dns-limitations + Kube_URL https://kubernetes.default.svc.cluster.local:443 + Buffer_Size ${K8S_BUFFER_SIZE} + K8S-Logging.Exclude ${K8S_LOGGING_EXCLUDE} + Labels Off + Annotations Off + + [FILTER] + Name nest + Match * + Alias kubernetes-attribute-lifter + Operation lift + Nested_under kubernetes + + [FILTER] + Name record_modifier + Match * + Alias node-attributes-enricher-filter + Record cluster_name "${CLUSTER_NAME}" + Allowlist_key container_name + Allowlist_key namespace_name + Allowlist_key pod_name + Allowlist_key stream + Allowlist_key message + Allowlist_key log + + outputs: | + [OUTPUT] + Name newrelic + Match * + Alias newrelic-logs-forwarder + licenseKey ${LICENSE_KEY} + endpoint ${ENDPOINT} + lowDataMode ${LOW_DATA_MODE} + sendMetrics ${SEND_OUTPUT_PLUGIN_METRICS} + Retry_Limit ${RETRY_LIMIT} + +# extraOutputs: | +# [OUTPUT] +# Name null +# Match * + +# parsers: | +# [PARSER] +# Name my_custom_parser +# Format json +# Time_Key time +# Time_Format %Y-%m-%dT%H:%M:%S.%L +# Time_Keep On + metricInstrumentation: | + [INPUT] + name prometheus_scrape + Alias fb-metrics-collector + host 127.0.0.1 + port 2020 + tag fb_metrics + metrics_path /api/v2/metrics/prometheus + scrape_interval 10s + + [OUTPUT] + Name prometheus_remote_write + Match fb_metrics + Alias fb-metrics-forwarder + Host ${METRICS_HOST} + Port 443 + Uri /prometheus/v1/write?prometheus_server=${CLUSTER_NAME} + Header Authorization Bearer ${LICENSE_KEY} + Tls On + # Windows pods using prometheus_remote_write currently have issues if TLS verify is On + Tls.verify Off + # User-defined labels + add_label app fluent-bit + add_label cluster_name "${CLUSTER_NAME}" + add_label pod_name ${HOSTNAME} + add_label node_name ${NODE_NAME} + add_label source kubernetes + +image: + repository: newrelic/newrelic-fluentbit-output +# registry: my_registry + tag: "" + pullPolicy: IfNotPresent + ## See https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod + pullSecrets: [] +# - name: regsecret + +# By default, the Linux DaemonSet will always be deployed, while the Windows DaemonSet(s) won't. +enableLinux: true +enableWindows: false +# For every entry in this Windows OS list, we will create an independent DaemonSet which will get deployed +# on Windows nodes running each specific Windows version and build number. Note that +# Windows containers can only be executed on hosts running the exact same Windows version and build number, +# because Kubernetes only supports process isolation and not Hyper-V isolation (as of September 2021) +windowsOsList: + # We aim to support (limited to LTSC2019/LTSC2022 using GitHub actions, see https://github.com/actions/runner-images/tree/main/images/win): + # https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/#windows-os-version-support + - version: ltsc2019 + imageTagSuffix: windows-ltsc-2019 + buildNumber: 10.0.17763 + - version: ltsc2022 + imageTagSuffix: windows-ltsc-2022 + buildNumber: 10.0.20348 + +# Default set of resources assigned to the DaemonSet pods +resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 250m + memory: 64Mi + +rbac: + # Specifies whether RBAC resources should be created + create: true + pspEnabled: false + +serviceAccount: + # Specifies whether a ServiceAccount should be created + create: + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + name: + # Specify any annotations to add to the ServiceAccount + annotations: {} + +# Optionally configure ports to expose metrics on /api/v1/metrics/prometheus +# See - https://docs.fluentbit.io/manual/administration/monitoring +exposedPorts: [] +# - containerPort: 2020 +# hostPort: 2020 +# name: metrics +# protocol: TCP + +# If you wish to provide additional labels to apply to the pod(s), specify +# them here +# podLabels: + +# Pod scheduling priority +# Ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +# priorityClassName: high-priority + +# Node affinity rules +# Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity +# +# IMPORTANT # +# ######### # +# When .Values.global.fargate == true, the chart will automatically add the required affinity rules to exclude +# the DaemonSet from Fargate nodes. There is no need to manually touch this property achieve this. +# This automatic exclusion will, however, not take place if this value is overridden: Setting this to a +# non-empty value WHEN deploying in EKS Fargate (global.fargate == true) requires the user to manually +# include in their custom ruleset an exclusion for nodes with "eks.amazonaws.com/compute-type: fargate", as +# the New Relic DaemonSet MUST NOT be deployed on fargate nodes, as the operator takes care of injecting it +# as a sidecar instead. +# Please refer to the daemonset.yaml template for more details on how to achieve this. +nodeAffinity: {} + +# Node labels for pod assignment +# Ref: https://kubernetes.io/docs/user-guide/node-selection/ +# Note that the Linux DaemonSet already contains a node selector label based on their OS (kubernetes.io/os: linux). +nodeSelector: {} + +# Note that the Windows DaemonSet already contains a node selector label based on their OS (kubernetes.io/os: windows). +# and build number (node.kubernetes.io/windows-build: {{ .buildNumber }}, to ensure that each version of the DaemonSet +# gets deployed only on those Windows nodes running the exact same Windows version and build number. Note that +# Windows containers can only be executed on hosts running the exact same Windows version and build number. +windowsNodeSelector: {} + +# These are default tolerations to be able to run the New Relic Kubernetes integration. +tolerations: + - operator: "Exists" + effect: "NoSchedule" + - operator: "Exists" + effect: "NoExecute" + +updateStrategy: RollingUpdate + +# Sends data to staging, can be set as a global. +# global.nrStaging +nrStaging: false + +daemonSet: + # Annotations to add to the DaemonSet. + annotations: {} + +# Annotations to add to the resulting Pods of the DaemonSet. +podAnnotations: {} + +# When low data mode is enabled only minimal attributes are added to the logs. Kubernetes labels and +# annotations are not included. The plugin.type, plugin.version and plugin.source attributes are minified +# into the plugin.source attribute. +# Can be set as a global: global.lowDataMode +# lowDataMode: false + +extraVolumes: [] +# - name: systemdlog +# hostPath: +# path: /run/log/journal + +extraVolumeMounts: [] +# - name: systemdlog +# mountPath: /run/log/journal + +initContainers: +# - name: init +# image: busybox +# command: ["sh", "-c", 'echo "hello world"'] + +windows: + initContainers: +# - name: init +# image: ... +# command: [...] + +# -- Sets pod dnsConfig. Can also be configured with `global.dnsConfig` +dnsConfig: {} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/Chart.yaml new file mode 100644 index 000000000..acd3077d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +appVersion: 2.1.4 +description: A Helm chart for the New Relic Pixie integration. +home: https://hub.docker.com/u/newrelic +icon: https://newrelic.com/assets/newrelic/source/NewRelic-logo-square.svg +keywords: +- newrelic +- pixie +- monitoring +maintainers: +- name: nserrino +- name: philkuz +- name: htroisi +- name: vuqtran88 +name: newrelic-pixie +sources: +- https://github.com/newrelic/ +version: 2.1.4 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/README.md new file mode 100644 index 000000000..228a3676d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/README.md @@ -0,0 +1,166 @@ +# newrelic-pixie + +## Chart Details + +This chart will deploy the New Relic Pixie Integration. + +IMPORTANT: In order to retrieve the Pixie cluster id from the `pl-cluster-secrets` the integration needs to be deployed in the same namespace as Pixie. By default, Pixie is installed in the `pl` namespace. Alternatively the `clusterId` can be configured manually when installing the chart. In this case the integration can be deployed to any namespace. + +## Configuration + +| Parameter | Description | Default | +| ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| `global.cluster` - `cluster` | The cluster name for the Kubernetes cluster. Required. | | +| `global.licenseKey` - `licenseKey` | The New Relic license key (stored in a secret). Required. | | +| `global.lowDataMode` - `lowDataMode` | If `true`, the integration performs heavier sampling on the Pixie span data and sets the collect interval to 15 seconds instead of 10 seconds. | false | +| `global.nrStaging` - `nrStaging` | Send data to staging (requires a staging license key). | false | +| `apiKey` | The Pixie API key (stored in a secret). Required. | | +| `clusterId` | The Pixie cluster id. Optional. Read from the `pl-cluster-secrets` secret if empty. | | +| `endpoint` | The Pixie endpoint. Required when using Pixie Open Source. | | +| `verbose` | Whether the integration should run in verbose mode or not. | false | +| `global.customSecretName` - `customSecretName` | Name of an existing Secret object, not created by this chart, where the New Relic license is stored | | +| `global.customSecretLicenseKey` - `customSecretLicenseKey` | Key in the existing Secret object, indicated by `customSecretName`, where the New Relic license key is stored. | | +| `image.pullSecrets` | Image pull secrets. | `nil` | +| `customSecretApiKeyName` | Name of an existing Secret object, not created by this chart, where the Pixie API key is stored. | | +| `customSecretApiKeyKey` | Key in the existing Secret object, indicated by `customSecretApiKeyName`, where the Pixie API key is stored. | | +| `podLabels` | Labels added to each Job pod | `{}` | +| `podAnnotations` | Annotations added to each Job pod | `{}` | +| `job.annotations` | Annotations added to the `newrelic-pixie` Job resource | `{}` | +| `job.labels` | Annotations added to the `newrelic-pixie` Job resource | `{}` | +| `nodeSelector` | Node label to use for scheduling. | `{}` | +| `tolerations` | List of node taints to tolerate (requires Kubernetes >= 1.6). | `[]` | +| `affinity` | Node affinity to use for scheduling. | `{}` | +| `proxy` | Set proxy to connect to Pixie Cloud and New Relic. | | +| `customScripts` | YAML containing custom scripts for long-term data retention. The results of the custom scripts will be stored in New Relic. See [custom scripts](#custom-scripts) for YAML format. | `{}` | +| `customScriptsConfigMap` | Name of an existing ConfigMap object containing custom script for long-term data retention. This configuration takes precedence over `customScripts`. | | +| `excludeNamespacesRegex` | Observability data for namespaces matching this RE2 regex is not sent to New Relic. If empty, observability data for all namespaces is sent to New Relic. | | +| `excludePodsRegex` | Observability data for pods (across all namespaces) matching this RE2 regex is not sent to New Relic. If empty, observability data for all pods (in non-excluded namespaces) is sent to New Relic. | | + +## Example + +Make sure you have [added the New Relic chart repository.](../../README.md#installing-charts) + +Then, to install this chart, run the following command: + +```sh +helm install newrelic/newrelic-pixie \ + --set cluster= \ + --set licenseKey= \ + --set apiKey= \ + --namespace pl \ + --generate-name +``` + +## Globals + +**Important:** global parameters have higher precedence than locals with the same name. + +These are meant to be used when you are writing a chart with subcharts. It helps to avoid +setting values multiple times on different subcharts. + +More information on globals and subcharts can be found at [Helm's official documentation](https://helm.sh/docs/topics/chart_template_guide/subcharts_and_globals/). + +| Parameter | +| ------------------------------- | +| `global.cluster` | +| `global.licenseKey` | +| `global.customSecretName` | +| `global.customSecretLicenseKey` | +| `global.lowDataMode` | +| `global.nrStaging` | + +## Custom scripts + +Custom scripts can either be configured directly in `customScripts` or be provided through an existing ConfigMap `customScriptsConfigMap`. + +The entries in the ConfigMap should contain file-like keys with the `.yaml` extension. Each file in the ConfigMap should be valid YAML and contain the following keys: + + * name (string): the name of the script + * description (string): description of the script + * frequencyS (int): frequency to execute the script in seconds + * scripts (string): the actual PXL script to execute + * addExcludes (optional boolean, `false` by default): add pod and namespace excludes to the custom script + +For more detailed information about the custom scripts see [the New Relic Pixie integration repo](https://github.com/newrelic/newrelic-pixie-integration/). + +```yaml +customScripts: + custom1.yaml: | + name: "custom1" + description: "Custom script 1" + frequencyS: 60 + script: | + import px + + df = px.DataFrame(table='http_events', start_time=px.plugin.start_time) + + ns_prefix = df.ctx['namespace'] + '/' + df.container = df.ctx['container_name'] + df.pod = px.strip_prefix(ns_prefix, df.ctx['pod']) + df.service = px.strip_prefix(ns_prefix, df.ctx['service']) + df.namespace = df.ctx['namespace'] + + df.status_code = df.resp_status + + df = df.groupby(['status_code', 'pod', 'container','service', 'namespace']).agg( + latency_min=('latency', px.min), + latency_max=('latency', px.max), + latency_sum=('latency', px.sum), + latency_count=('latency', px.count), + time_=('time_', px.max), + ) + + df.latency_min = df.latency_min / 1000000 + df.latency_max = df.latency_max / 1000000 + df.latency_sum = df.latency_sum / 1000000 + + df.cluster_name = px.vizier_name() + df.cluster_id = px.vizier_id() + df.pixie = 'pixie' + + px.export( + df, px.otel.Data( + resource={ + 'service.name': df.service, + 'k8s.container.name': df.container, + 'service.instance.id': df.pod, + 'k8s.pod.name': df.pod, + 'k8s.namespace.name': df.namespace, + 'px.cluster.id': df.cluster_id, + 'k8s.cluster.name': df.cluster_name, + 'instrumentation.provider': df.pixie, + }, + data=[ + px.otel.metric.Summary( + name='http.server.duration', + description='measures the duration of the inbound HTTP request', + # Unit is not supported yet + # unit='ms', + count=df.latency_count, + sum=df.latency_sum, + quantile_values={ + 0.0: df.latency_min, + 1.0: df.latency_max, + }, + attributes={ + 'http.status_code': df.status_code, + }, + )], + ), + ) +``` + + +## Resources + +The default set of resources assigned to the pods is shown below: + +```yaml +resources: + limits: + memory: 250M + requests: + cpu: 100m + memory: 250M +``` + diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/ci/test-values.yaml new file mode 100644 index 000000000..580f9b0ba --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/ci/test-values.yaml @@ -0,0 +1,5 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + apiKey: 1234567890abcdef + cluster: test-cluster +clusterId: foobar diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/NOTES.txt b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/NOTES.txt new file mode 100644 index 000000000..d54283889 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/NOTES.txt @@ -0,0 +1,27 @@ +{{- if (include "newrelic-pixie.areValuesValid" .) }} + +Your deployment of the New Relic Pixie integration is complete. + +Please ensure this integration is deployed in the same namespace +as Pixie or manually specify the clusterId. +{{- else -}} +############################################################### +#### ERROR: You did not set all the required values. #### +############################################################### + +This deployment will be incomplete until you set all the required values: + +* Cluster name +* New Relic license key +* Pixie API key + +For a simple installation to be fixed, run: + + helm upgrade {{ .Release.Name }} \ + --set cluster=YOUR-CLUSTER-NAME \ + --set licenseKey=YOUR-LICENSE-KEY \ + --set apiKey=YOUR-API-KEY \ + -n {{ .Release.Namespace }} \ + newrelic/newrelic-pixie + +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/_helpers.tpl new file mode 100644 index 000000000..40b9c68df --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/_helpers.tpl @@ -0,0 +1,172 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "newrelic-pixie.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{- define "newrelic-pixie.namespace" -}} +{{- if .Values.namespace -}} + {{- .Values.namespace -}} +{{- else -}} + {{- .Release.Namespace | default "pl" -}} +{{- end -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic-pixie.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if ne $name .Release.Name -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* Generate basic labels */}} +{{- define "newrelic-pixie.labels" }} +app: {{ template "newrelic-pixie.name" . }} +app.kubernetes.io/name: {{ include "newrelic-pixie.name" . }} +chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} +heritage: {{.Release.Service }} +release: {{.Release.Name }} +{{- end }} + +{{- define "newrelic-pixie.cluster" -}} +{{- if .Values.global -}} + {{- if .Values.global.cluster -}} + {{- .Values.global.cluster -}} + {{- else -}} + {{- .Values.cluster | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.cluster | default "" -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-pixie.nrStaging" -}} +{{- if .Values.global }} + {{- if .Values.global.nrStaging }} + {{- .Values.global.nrStaging -}} + {{- end -}} +{{- else if .Values.nrStaging }} + {{- .Values.nrStaging -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-pixie.licenseKey" -}} +{{- if .Values.global}} + {{- if .Values.global.licenseKey }} + {{- .Values.global.licenseKey -}} + {{- else -}} + {{- .Values.licenseKey | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.licenseKey | default "" -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-pixie.apiKey" -}} +{{- if .Values.global}} + {{- if .Values.global.apiKey }} + {{- .Values.global.apiKey -}} + {{- else -}} + {{- .Values.apiKey | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.apiKey | default "" -}} +{{- end -}} +{{- end -}} + +{{- /* +adapted from https://github.com/newrelic/helm-charts/blob/af747af93fb5b912374196adc59b552965b6e133/library/common-library/templates/_low-data-mode.tpl +TODO: actually use common-library chart dep +*/ -}} +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic-pixie.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the customSecretName where the New Relic license is being stored. +*/}} +{{- define "newrelic-pixie.customSecretName" -}} +{{- if .Values.global }} + {{- if .Values.global.customSecretName }} + {{- .Values.global.customSecretName -}} + {{- else -}} + {{- .Values.customSecretName | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.customSecretName | default "" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the customSecretApiKeyName where the Pixie API key is being stored. +*/}} +{{- define "newrelic-pixie.customSecretApiKeyName" -}} + {{- .Values.customSecretApiKeyName | default "" -}} +{{- end -}} + +{{/* +Return the customSecretLicenseKey +*/}} +{{- define "newrelic-pixie.customSecretLicenseKey" -}} +{{- if .Values.global }} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- else -}} + {{- .Values.customSecretLicenseKey | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.customSecretLicenseKey | default "" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the customSecretApiKeyKey +*/}} +{{- define "newrelic-pixie.customSecretApiKeyKey" -}} + {{- .Values.customSecretApiKeyKey | default "" -}} +{{- end -}} + +{{/* +Returns if the template should render, it checks if the required values +licenseKey and cluster are set. +*/}} +{{- define "newrelic-pixie.areValuesValid" -}} +{{- $cluster := include "newrelic-pixie.cluster" . -}} +{{- $licenseKey := include "newrelic-pixie.licenseKey" . -}} +{{- $apiKey := include "newrelic-pixie.apiKey" . -}} +{{- $customSecretName := include "newrelic-pixie.customSecretName" . -}} +{{- $customSecretLicenseKey := include "newrelic-pixie.customSecretLicenseKey" . -}} +{{- $customSecretApiKeyKey := include "newrelic-pixie.customSecretApiKeyKey" . -}} +{{- and (or (and $licenseKey $apiKey) (and $customSecretName $customSecretLicenseKey $customSecretApiKeyKey)) $cluster}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/configmap.yaml new file mode 100644 index 000000000..19f7fe61a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/configmap.yaml @@ -0,0 +1,12 @@ +{{- if (include "newrelic-pixie.areValuesValid" .) }} +{{- if .Values.customScripts }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ template "newrelic-pixie.namespace" . }} + labels: {{ include "newrelic-pixie.labels" . | indent 4 }} + name: {{ template "newrelic-pixie.fullname" . }}-scripts +data: +{{- toYaml .Values.customScripts | nindent 2 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/job.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/job.yaml new file mode 100644 index 000000000..89b97514f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/job.yaml @@ -0,0 +1,164 @@ +{{- if (include "newrelic-pixie.areValuesValid" .) }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "newrelic-pixie.fullname" . }} + namespace: {{ template "newrelic-pixie.namespace" . }} + labels: + {{- include "newrelic-pixie.labels" . | trim | nindent 4}} + {{- if ((.Values.job).labels) }} + {{- toYaml .Values.job.labels | nindent 4 }} + {{- end }} + {{- if ((.Values.job).annotations) }} + annotations: + {{ toYaml .Values.job.annotations | nindent 4 | trim }} + {{- end }} +spec: + backoffLimit: 4 + ttlSecondsAfterFinished: 600 + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "newrelic-pixie.name" . }} + release: {{.Release.Name }} + {{- if .Values.podLabels }} + {{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} + {{- if .Values.podAnnotations }} + annotations: + {{- toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + spec: + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- toYaml .Values.image.pullSecrets | nindent 8 }} + {{- end }} + restartPolicy: Never + initContainers: + - name: cluster-registration-wait + image: gcr.io/pixie-oss/pixie-dev-public/curl:1.0 + command: ['sh', '-c', 'set -x; + URL="https://${SERVICE_NAME}:${SERVICE_PORT}/readyz"; + until [ $(curl -m 0.5 -s -o /dev/null -w "%{http_code}" -k ${URL}) -eq 200 ]; do + echo "Waiting for cluster registration. If this takes too long check the vizier-cloud-connector logs." + sleep 2; + done; + '] + env: + # The name of the Pixie service which connects to Pixie Cloud for cluster registration. + - name: SERVICE_NAME + value: "vizier-cloud-connector-svc" + - name: SERVICE_PORT + value: "50800" + containers: + - name: {{ template "newrelic-pixie.name" . }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + env: + - name: CLUSTER_NAME + value: {{ template "newrelic-pixie.cluster" . }} + - name: NR_LICENSE_KEY + valueFrom: + secretKeyRef: + {{- if (include "newrelic-pixie.licenseKey" .) }} + name: {{ template "newrelic-pixie.fullname" . }}-secrets + key: newrelicLicenseKey + {{- else }} + name: {{ include "newrelic-pixie.customSecretName" . }} + key: {{ include "newrelic-pixie.customSecretLicenseKey" . }} + {{- end }} + - name: PIXIE_API_KEY + valueFrom: + secretKeyRef: + {{- if (include "newrelic-pixie.apiKey" .) }} + name: {{ template "newrelic-pixie.fullname" . }}-secrets + key: pixieApiKey + {{- else }} + name: {{ include "newrelic-pixie.customSecretApiKeyName" . }} + key: {{ include "newrelic-pixie.customSecretApiKeyKey" . }} + {{- end }} + - name: PIXIE_CLUSTER_ID + {{- if .Values.clusterId }} + value: {{ .Values.clusterId -}} + {{- else }} + valueFrom: + secretKeyRef: + key: cluster-id + name: pl-cluster-secrets + {{- end }} + {{- if .Values.verbose }} + - name: VERBOSE + value: "true" + {{- end }} + {{- if (include "newrelic-pixie.lowDataMode" .) }} + - name: COLLECT_INTERVAL_SEC + value: "15" + - name: HTTP_SPAN_LIMIT + value: "750" + - name: DB_SPAN_LIMIT + value: "250" + {{- else }} + - name: COLLECT_INTERVAL_SEC + value: "10" + - name: HTTP_SPAN_LIMIT + value: "1500" + - name: DB_SPAN_LIMIT + value: "500" + {{- end }} + {{- if (include "newrelic-pixie.nrStaging" .) }} + - name: NR_OTLP_HOST + value: "staging-otlp.nr-data.net:4317" + {{- end }} + {{- if or .Values.endpoint (include "newrelic-pixie.nrStaging" .) }} + - name: PIXIE_ENDPOINT + {{- if .Values.endpoint }} + value: {{ .Values.endpoint | quote }} + {{- else }} + value: "staging.withpixie.dev:443" + {{- end }} + {{- end }} + {{- if .Values.proxy }} + - name: HTTP_PROXY + value: {{ .Values.proxy | quote }} + - name: HTTPS_PROXY + value: {{ .Values.proxy | quote }} + {{- end }} + {{- if .Values.excludePodsRegex }} + - name: EXCLUDE_PODS_REGEX + value: {{ .Values.excludePodsRegex | quote }} + {{- end }} + {{- if .Values.excludeNamespacesRegex }} + - name: EXCLUDE_NAMESPACES_REGEX + value: {{ .Values.excludeNamespacesRegex | quote }} + {{- end }} + {{- if .Values.resources }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + {{- end }} + {{- if or .Values.customScriptsConfigMap .Values.customScripts }} + volumeMounts: + - name: scripts + mountPath: "/scripts" + readOnly: true + volumes: + - name: scripts + configMap: + {{- if .Values.customScriptsConfigMap }} + name: {{ .Values.customScriptsConfigMap }} + {{- else }} + name: {{ template "newrelic-pixie.fullname" . }}-scripts + {{- end}} + {{- end }} + {{- if $.Values.nodeSelector }} + nodeSelector: + {{- toYaml $.Values.nodeSelector | nindent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: + {{- toYaml .Values.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: + {{- toYaml .Values.affinity | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/secret.yaml new file mode 100644 index 000000000..4d9561877 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/templates/secret.yaml @@ -0,0 +1,20 @@ +{{- if (include "newrelic-pixie.areValuesValid" .) }} +{{- $licenseKey := include "newrelic-pixie.licenseKey" . -}} +{{- $apiKey := include "newrelic-pixie.apiKey" . -}} +{{- if or $apiKey $licenseKey}} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ template "newrelic-pixie.namespace" . }} + labels: {{ include "newrelic-pixie.labels" . | indent 4 }} + name: {{ template "newrelic-pixie.fullname" . }}-secrets +type: Opaque +data: + {{- if $licenseKey }} + newrelicLicenseKey: {{ $licenseKey | b64enc }} + {{- end }} + {{- if $apiKey }} + pixieApiKey: {{ include "newrelic-pixie.apiKey" . | b64enc -}} + {{- end }} +{{- end }} +{{- end}} \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/tests/configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/tests/configmap.yaml new file mode 100644 index 000000000..ecba6363b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/tests/configmap.yaml @@ -0,0 +1,44 @@ +suite: test custom scripts ConfigMap +templates: + - templates/configmap.yaml +tests: + - it: ConfigMap is created + set: + cluster: "test-cluster" + licenseKey: "license123" + apiKey: "api123" + customScripts: + custom1.yaml: | + name: "custom1" + description: "Custom script 1" + frequencyS: 60 + script: | + import px + df = px.DataFrame(table='http_events', start_time=px.plugin.start_time) + asserts: + - isKind: + of: ConfigMap + - equal: + path: data.custom1\.yaml + value: |- + name: "custom1" + description: "Custom script 1" + frequencyS: 60 + script: | + import px + df = px.DataFrame(table='http_events', start_time=px.plugin.start_time) + - equal: + path: metadata.name + value: RELEASE-NAME-newrelic-pixie-scripts + - equal: + path: metadata.namespace + value: NAMESPACE + - it: ConfigMap is empty + set: + cluster: "test-cluster" + licenseKey: "license123" + apiKey: "api123" + customScripts: {} + asserts: + - hasDocuments: + count: 0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/tests/jobs.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/tests/jobs.yaml new file mode 100644 index 000000000..03a3d86b8 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/tests/jobs.yaml @@ -0,0 +1,138 @@ +suite: test job +templates: + - templates/job.yaml +tests: + - it: Test primary fields of job + set: + cluster: "test-cluster" + licenseKey: "license123" + apiKey: "api123" + image: + tag: "latest" + asserts: + - isKind: + of: Job + - equal: + path: "metadata.name" + value: "RELEASE-NAME-newrelic-pixie" + - equal: + path: "metadata.namespace" + value: "NAMESPACE" + - equal: + path: "spec.template.spec.containers[0].image" + value: "newrelic/newrelic-pixie-integration:latest" + - equal: + path: "spec.template.spec.containers[0].env" + value: + - name: CLUSTER_NAME + value: test-cluster + - name: NR_LICENSE_KEY + valueFrom: + secretKeyRef: + key: newrelicLicenseKey + name: RELEASE-NAME-newrelic-pixie-secrets + - name: PIXIE_API_KEY + valueFrom: + secretKeyRef: + key: pixieApiKey + name: RELEASE-NAME-newrelic-pixie-secrets + - name: PIXIE_CLUSTER_ID + valueFrom: + secretKeyRef: + key: cluster-id + name: pl-cluster-secrets + - isEmpty: + path: "spec.template.spec.containers[0].volumeMounts" + - isEmpty: + path: "spec.template.spec.volumes" + - it: Job with clusterId + set: + cluster: "test-cluster" + licenseKey: "license123" + apiKey: "api123" + clusterId: "cid123" + asserts: + - equal: + path: "spec.template.spec.containers[0].env" + value: + - name: CLUSTER_NAME + value: test-cluster + - name: NR_LICENSE_KEY + valueFrom: + secretKeyRef: + key: newrelicLicenseKey + name: RELEASE-NAME-newrelic-pixie-secrets + - name: PIXIE_API_KEY + valueFrom: + secretKeyRef: + key: pixieApiKey + name: RELEASE-NAME-newrelic-pixie-secrets + - name: PIXIE_CLUSTER_ID + value: "cid123" + - it: Job with Pixie endpoint + set: + cluster: "test-cluster" + licenseKey: "license123" + apiKey: "api123" + clusterId: "cid123" + endpoint: "withpixie.ai:443" + asserts: + - equal: + path: "spec.template.spec.containers[0].env" + value: + - name: CLUSTER_NAME + value: test-cluster + - name: NR_LICENSE_KEY + valueFrom: + secretKeyRef: + key: newrelicLicenseKey + name: RELEASE-NAME-newrelic-pixie-secrets + - name: PIXIE_API_KEY + valueFrom: + secretKeyRef: + key: pixieApiKey + name: RELEASE-NAME-newrelic-pixie-secrets + - name: PIXIE_CLUSTER_ID + value: "cid123" + - name: PIXIE_ENDPOINT + value: "withpixie.ai:443" + - it: Job with custom scripts + set: + cluster: "test-cluster" + licenseKey: "license123" + apiKey: "api123" + customScripts: + custom1.yaml: | + name: "custom1" + asserts: + - equal: + path: "spec.template.spec.containers[0].volumeMounts" + value: + - name: scripts + mountPath: "/scripts" + readOnly: true + - equal: + path: "spec.template.spec.volumes[0]" + value: + name: scripts + configMap: + name: RELEASE-NAME-newrelic-pixie-scripts + - it: Job with custom script in defined ConfigMap + set: + cluster: "test-cluster" + licenseKey: "license123" + apiKey: "api123" + customScriptsConfigMap: "myconfigmap" + asserts: + - equal: + path: "spec.template.spec.containers[0].volumeMounts" + value: + - name: scripts + mountPath: "/scripts" + readOnly: true + - equal: + path: "spec.template.spec.volumes[0]" + value: + name: scripts + configMap: + name: myconfigmap diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/values.yaml new file mode 100644 index 000000000..4103d54e9 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-pixie/values.yaml @@ -0,0 +1,70 @@ +# IMPORTANT: The Kubernetes cluster name +# https://docs.newrelic.com/docs/kubernetes-monitoring-integration +# cluster: "" + +# The New Relic license key +# licenseKey: "" + +# The Pixie API key +# apiKey: "" + +# The Pixie Cluster Id +# clusterId: + +# The Pixie endpoint +# endpoint: + +# If you already have a secret where the New Relic license key is stored, indicate its name here +# customSecretName: +# The key in the customSecretName secret that contains the New Relic license key +# customSecretLicenseKey: +# If you already have a secret where the Pixie API key is stored, indicate its name here +# customSecretApiKeyName: +# The key in the customSecretApiKeyName secret that contains the Pixie API key +# customSecretApiKeyKey: + +image: + repository: newrelic/newrelic-pixie-integration + tag: "" + pullPolicy: IfNotPresent + pullSecrets: [] + # - name: regsecret + +resources: + limits: + memory: 250M + requests: + cpu: 100m + memory: 250M + +# -- Annotations to add to the pod. +podAnnotations: {} +# -- Additional labels for chart pods +podLabels: {} + +job: + # job.annotations -- Annotations to add to the Job. + annotations: {} + # job.labels -- Labels to add to the Job. + labels: {} + +proxy: {} + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +customScripts: {} +# Optionally the scripts can be provided in an already existing ConfigMap: +# customScriptsConfigMap: + +excludeNamespacesRegex: +excludePodsRegex: + +# When low data mode is enabled the integration performs heavier sampling on the Pixie span data +# and sets the collect interval to 15 seconds instead of 10 seconds. +# Can be set as a global: global.lowDataMode or locally as newrelic-pixie.lowDataMode +# @default -- false +lowDataMode: diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/Chart.lock new file mode 100644 index 000000000..18bbb9ef4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +digest: sha256:fa87cb007564a39a72739a3e850a91d6b03c0fc27a1115deac042b3ef77b4142 +generated: "2024-06-21T18:14:01.260095101Z" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/Chart.yaml new file mode 100644 index 000000000..507183a3e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/Chart.yaml @@ -0,0 +1,22 @@ +annotations: + configuratorVersion: 1.17.2 +apiVersion: v2 +appVersion: v2.37.8 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +description: A Helm chart to deploy Prometheus with New Relic Prometheus Configurator. +keywords: +- newrelic +- prometheus +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +name: newrelic-prometheus-agent +type: application +version: 1.14.2 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/README.md new file mode 100644 index 000000000..069b9a79b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/README.md @@ -0,0 +1,244 @@ +# newrelic-prometheus-agent + +A Helm chart to deploy Prometheus with New Relic Prometheus Configurator. + +# Description + +This chart deploys Prometheus Server in Agent mode configured by the `newrelic-prometheus-configurator`. + +The solution is deployed as a StatefulSet for sharding proposes. +Each Pod will execute the `newrelic-prometheus-configurator` init container which will convert the provided config to a config file in the Prometheus format. Once the init container finishes and saves the config in a shared volume, the container running Prometheus in Agent mode will start. + +```mermaid +graph LR + subgraph pod[Pod] + direction TB + subgraph volume[shared volume] + plain[Prometheus Config] + end + + subgraph init-container[init Container] + configurator[Configurator] --> plain[Prometheus Config] + end + + subgraph container[Main Container] + plain[Prometheus Config] --> prom-agent[Prometheus-Agent] + end + + end + + subgraph configMap + NewRelic-Config --> configurator[Configurator] + end + +classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; +classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; +classDef pod fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; +class configurator,init-container,container,prom-agent k8s; +class volume plain; +class pod pod; + +``` + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add newrelic-prometheus https://newrelic.github.io/newrelic-prometheus-configurator +helm upgrade --install newrelic newrelic-prometheus/newrelic-prometheus-agent -f your-custom-values.yaml +``` + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Chart particularities + +### Configuration + +The configuration used is similar to the [Prometheus configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/), but it includes some syntactic sugar to make easy to set up some special use-cases like Kubernetes targets, sharding and some New Relic related settings like remote write endpoints. + +The configurator will create [scrape_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config), [relabel_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config), [remote_write](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write) and other entries based on the defined configuration. + +As general rules: +- Configs parameters having the same name as the [Prometheus configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/) should have similar behavior. For example, the `tls_config` defined inside a `Kubernetes.jobs` will have the same definition as [tls_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#tls_config) of Prometheus and will affect all targets scraped by that job. +- Configs starting with `extra_` prefix will be appended to the ones created by the Configurator. For example, the relabel configs defined in `extra_relabel_config` on the Kubernetes section will be appended to the end of the list that is already being generated by the Configurator for filtering, sharding, metadata decoration, etc. + +### Default Kubernetes jobs configuration + +By default, some Kubernetes objects are discovered and scraped by Prometheus. Taking into account the snippet from `values.yaml` below: + +```yaml + integrations_filter: + enabled: true + source_labels: ["app.kubernetes.io/name", "app.newrelic.io/name", "k8s-app"] + app_values: ["redis", "traefik", "calico", "nginx", "coredns", "etcd", "cockroachdb", "velero", "harbor", "argocd"] + jobs: + - job_name_prefix: default + target_discovery: + pod: true + endpoints: true + filter: + annotations: + prometheus.io/scrape: true + - job_name_prefix: newrelic + integrations_filter: + enabled: false + target_discovery: + pod: true + endpoints: true + filter: + annotations: + newrelic.io/scrape: true +``` + +All pods and endpoints with the `newrelic.io/scrape: true` annotation will be scraped by default. + +Moreover, the solution will scrape as well all pods and endpoints with the `prometheus.io/scrape: true` annotations and +having one of the labels matching the integrations_filter configuration. + +Notice that at any point you can turn off the integrations filters and scrape all pods and services annotated with +`prometheus.io/scrape: true` by setting `config.kubernetes.integrations_filter.integrations_filter: false` or turning +it off in any specific job. + +### Kubernetes job examples + +#### API Server metrics +By default, the API Server Service named `kubernetes` is created in the `default` namespace. The following configuration will scrape metrics from all endpoints behind the mentioned service using the Prometheus Pod bearer token as Authorization Header: + +```yaml +config: + kubernetes: + jobs: + - job_name_prefix: apiserver + target_discovery: + endpoints: true + extra_relabel_config: + # Filter endpoints on `default` namespace associated to `kubernetes` service. + - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name] + action: keep + regex: default;kubernetes + + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecure_skip_verify: true + authorization: + credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token +``` + +### Metrics Filtering + +Check [docs](https://github.com/newrelic/newrelic-prometheus-configurator/blob/main/docs/MetricsFilters.md) for a detailed explanation and examples of how to filter metrics and labels. + +### Self metrics + +By default, it is defined as a job in `static_target.jobs` to obtain self-metrics. Particularly, a snippet like the one +below is used. If you define your own static_targets jobs, it is important to also include this kind of job in order +to keep getting self-metrics. + +```yaml +config: + static_targets: + jobs: + - job_name: self-metrics + targets: + - "localhost:9090" + extra_metric_relabel_config: + - source_labels: [__name__] + regex: "" + action: keep +``` + +### Low data mode + +There are two mechanisms to reduce the amount of data that this integration sends to New Relic. See this snippet from the `values.yaml` file: +```yaml +lowDataMode: false + +config: + common: + scrape_interval: 30s +``` + +You might set `lowDataMode` flag to `true` (it will filter some metrics which can also be collected using New Relic Kubernetes integration), check +`values.yaml` for details. + +It is also possible to adjust how frequently Prometheus scrapes the targets by setting up the` config.common.scrape_interval` value. + +### Affinities and tolerations + +The New Relic common library allows you to set affinities, tolerations, and node selectors globally using e.g. `.global.affinity` to ease the configuration +when you use this chart using `nri-bundle`. This chart has an extra level of granularity to the components that it deploys: +control plane, ksm, and kubelet. + +Take this snippet as an example: +```yaml +global: + affinity: {} +affinity: {} +``` + +The order to set the affinity is to set `affinity` field (at root level), if that value is empty, the chart fallbacks to `global.affinity`. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Sets pod/node affinities set almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) | +| cluster | string | `""` | Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster`. Note it will be set as an external label in prometheus configuration, it will have precedence over `config.common.external_labels.cluster_name` and `customAttributes.cluster_name``. | +| config | object | See `values.yaml` | It holds the New Relic Prometheus configuration. Here you can easily set up Prometheus to get set metrics, discover ponds and endpoints Kubernetes and send metrics to New Relic using remote-write. | +| config.common | object | See `values.yaml` | Include global configuration for Prometheus agent. | +| config.common.scrape_interval | string | `"30s"` | How frequently to scrape targets by default, unless a different value is specified on the job. | +| config.extra_remote_write | object | `nil` | It includes additional remote-write configuration. Note this configuration is not parsed, so valid [prometheus remote_write configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write) should be provided. | +| config.extra_scrape_configs | list | `[]` | It is possible to include extra scrape configuration in [prometheus format](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config). Please note, it should be a valid Prometheus configuration which will not be parsed by the chart. WARNING extra_scrape_configs is a raw Prometheus config. Therefore, the metrics collected thanks to it will not have by default the metadata (pod_name, service_name, ...) added by the configurator for the static or kubernetes jobs. This configuration should be used as a workaround whenever kubernetes and static job do not cover a particular use-case. | +| config.kubernetes | object | See `values.yaml` | It allows defining scrape jobs for Kubernetes in a simple way. | +| config.kubernetes.integrations_filter.app_values | list | `["redis","traefik","calico","nginx","coredns","kube-dns","etcd","cockroachdb","velero","harbor","argocd"]` | app_values used to create the regex used in the relabel config added by the integration filters configuration. Note that a single regex will be created from this list, example: '.*(?i)(app1|app2|app3).*' | +| config.kubernetes.integrations_filter.enabled | bool | `true` | enabling the integration filters, merely the targets having one of the specified labels matching one of the values of app_values are scraped. Each job configuration can override this default. | +| config.kubernetes.integrations_filter.source_labels | list | `["app.kubernetes.io/name","app.newrelic.io/name","k8s-app"]` | source_labels used to fetch label values in the relabel config added by the integration filters configuration | +| config.newrelic_remote_write | object | See `values.yaml` | Newrelic remote-write configuration settings. | +| config.static_targets | object | See `values.yaml`. | It allows defining scrape jobs for targets with static URLs. | +| config.static_targets.jobs | list | See `values.yaml`. | List of static target jobs. By default, it defines a job to get self-metrics. Please note, if you define `static_target.jobs` and would like to keep self-metrics you need to include a job like the one defined by default. | +| containerSecurityContext | object | `{}` | Sets security context (at container level). Can be configured also with `global.containerSecurityContext` | +| customAttributes | object | `{}` | Adds extra attributes to prometheus external labels. Can be configured also with `global.customAttributes`. Please note, values defined in `common.config.externar_labels` will have precedence over `customAttributes`. | +| customSecretLicenseKey | string | `""` | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` | +| customSecretName | string | `""` | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` | +| dnsConfig | object | `{}` | Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` | +| extraVolumeMounts | list | `[]` | Defines where to mount volumes specified with `extraVolumes` | +| extraVolumes | list | `[]` | Volumes to mount in the containers | +| fullnameOverride | string | `""` | Override the full name of the release | +| hostNetwork | bool | `false` | Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` | +| images.configurator | object | See `values.yaml` | Image for New Relic configurator. | +| images.prometheus | object | See `values.yaml` | Image for prometheus which is executed in agent mode. | +| images.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | +| labels | object | `{}` | Additional labels for chart objects. Can be configured also with `global.labels` | +| licenseKey | string | `""` | This set this license key to use. Can be configured also with `global.licenseKey` | +| lowDataMode | bool | false | Reduces the number of metrics sent in order to reduce costs. It can be configured also with `global.lowDataMode`. Specifically, it makes Prometheus stop reporting some Kubernetes cluster-specific metrics, you can see details in `static/lowdatamodedefaults.yaml`. | +| metric_type_override | object | `{"enabled":true}` | It holds the configuration for metric type override. If enabled, a series of metric relabel configs will be added to `config.newrelic_remote_write.extra_write_relabel_configs`, you can check the whole list in `static/metrictyperelabeldefaults.yaml` | +| nameOverride | string | `""` | Override the name of the chart | +| nodeSelector | object | `{}` | Sets pod's node selector almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) | +| nrStaging | bool | `false` | Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` | +| podAnnotations | object | `{}` | Annotations to be added to all pods created by the integration. | +| podLabels | object | `{}` | Additional labels for chart pods. Can be configured also with `global.podLabels` | +| podSecurityContext | object | `{}` | Sets security context (at pod level). Can be configured also with `global.podSecurityContext` | +| priorityClassName | string | `""` | Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` | +| rbac.create | bool | `true` | Whether the chart should automatically create the RBAC objects required to run. | +| rbac.pspEnabled | bool | `false` | Whether the chart should create Pod Security Policy objects. | +| resources | object | `{}` | Resource limits to be added to all pods created by the integration. | +| serviceAccount | object | See `values.yaml` | Settings controlling ServiceAccount creation. | +| serviceAccount.create | bool | `true` | Whether the chart should automatically create the ServiceAccount objects required to run. | +| sharding | string | See `values.yaml` | Set up Prometheus replicas to allow horizontal scalability. | +| tolerations | list | `[]` | Sets pod's tolerations to node taints almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) | +| verboseLog | bool | `false` | Sets the debug log to Prometheus and prometheus-configurator or all integrations if it is set globally. Can be configured also with `global.verboseLog` | + +## Maintainers + +* [juanjjaramillo](https://github.com/juanjjaramillo) +* [csongnr](https://github.com/csongnr) +* [dbudziwojskiNR](https://github.com/dbudziwojskiNR) diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/README.md.gotmpl new file mode 100644 index 000000000..8738b7329 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/README.md.gotmpl @@ -0,0 +1,209 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +# Description + +This chart deploys Prometheus Server in Agent mode configured by the `newrelic-prometheus-configurator`. + +The solution is deployed as a StatefulSet for sharding proposes. +Each Pod will execute the `newrelic-prometheus-configurator` init container which will convert the provided config to a config file in the Prometheus format. Once the init container finishes and saves the config in a shared volume, the container running Prometheus in Agent mode will start. + +```mermaid +graph LR + subgraph pod[Pod] + direction TB + subgraph volume[shared volume] + plain[Prometheus Config] + end + + subgraph init-container[init Container] + configurator[Configurator] --> plain[Prometheus Config] + end + + subgraph container[Main Container] + plain[Prometheus Config] --> prom-agent[Prometheus-Agent] + end + + end + + subgraph configMap + NewRelic-Config --> configurator[Configurator] + end + +classDef plain fill:#ddd,stroke:#fff,stroke-width:4px,color:#000; +classDef k8s fill:#326ce5,stroke:#fff,stroke-width:4px,color:#fff; +classDef pod fill:#fff,stroke:#bbb,stroke-width:2px,color:#326ce5; +class configurator,init-container,container,prom-agent k8s; +class volume plain; +class pod pod; + +``` + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add newrelic-prometheus https://newrelic.github.io/newrelic-prometheus-configurator +helm upgrade --install newrelic newrelic-prometheus/newrelic-prometheus-agent -f your-custom-values.yaml +``` + +{{ template "chart.sourcesSection" . }} + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Chart particularities + +### Configuration + +The configuration used is similar to the [Prometheus configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/), but it includes some syntactic sugar to make easy to set up some special use-cases like Kubernetes targets, sharding and some New Relic related settings like remote write endpoints. + +The configurator will create [scrape_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config), [relabel_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config), [remote_write](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write) and other entries based on the defined configuration. + +As general rules: +- Configs parameters having the same name as the [Prometheus configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/) should have similar behavior. For example, the `tls_config` defined inside a `Kubernetes.jobs` will have the same definition as [tls_config](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#tls_config) of Prometheus and will affect all targets scraped by that job. +- Configs starting with `extra_` prefix will be appended to the ones created by the Configurator. For example, the relabel configs defined in `extra_relabel_config` on the Kubernetes section will be appended to the end of the list that is already being generated by the Configurator for filtering, sharding, metadata decoration, etc. + +### Default Kubernetes jobs configuration + +By default, some Kubernetes objects are discovered and scraped by Prometheus. Taking into account the snippet from `values.yaml` below: + +```yaml + integrations_filter: + enabled: true + source_labels: ["app.kubernetes.io/name", "app.newrelic.io/name", "k8s-app"] + app_values: ["redis", "traefik", "calico", "nginx", "coredns", "etcd", "cockroachdb", "velero", "harbor", "argocd"] + jobs: + - job_name_prefix: default + target_discovery: + pod: true + endpoints: true + filter: + annotations: + prometheus.io/scrape: true + - job_name_prefix: newrelic + integrations_filter: + enabled: false + target_discovery: + pod: true + endpoints: true + filter: + annotations: + newrelic.io/scrape: true +``` + +All pods and endpoints with the `newrelic.io/scrape: true` annotation will be scraped by default. + +Moreover, the solution will scrape as well all pods and endpoints with the `prometheus.io/scrape: true` annotations and +having one of the labels matching the integrations_filter configuration. + +Notice that at any point you can turn off the integrations filters and scrape all pods and services annotated with +`prometheus.io/scrape: true` by setting `config.kubernetes.integrations_filter.integrations_filter: false` or turning +it off in any specific job. + +### Kubernetes job examples + +#### API Server metrics +By default, the API Server Service named `kubernetes` is created in the `default` namespace. The following configuration will scrape metrics from all endpoints behind the mentioned service using the Prometheus Pod bearer token as Authorization Header: + +```yaml +config: + kubernetes: + jobs: + - job_name_prefix: apiserver + target_discovery: + endpoints: true + extra_relabel_config: + # Filter endpoints on `default` namespace associated to `kubernetes` service. + - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name] + action: keep + regex: default;kubernetes + + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecure_skip_verify: true + authorization: + credentials_file: /var/run/secrets/kubernetes.io/serviceaccount/token +``` + +### Metrics Filtering + +Check [docs](https://github.com/newrelic/newrelic-prometheus-configurator/blob/main/docs/MetricsFilters.md) for a detailed explanation and examples of how to filter metrics and labels. + +### Self metrics + +By default, it is defined as a job in `static_target.jobs` to obtain self-metrics. Particularly, a snippet like the one +below is used. If you define your own static_targets jobs, it is important to also include this kind of job in order +to keep getting self-metrics. + +```yaml +config: + static_targets: + jobs: + - job_name: self-metrics + targets: + - "localhost:9090" + extra_metric_relabel_config: + - source_labels: [__name__] + regex: "" + action: keep +``` + +### Low data mode + +There are two mechanisms to reduce the amount of data that this integration sends to New Relic. See this snippet from the `values.yaml` file: +```yaml +lowDataMode: false + +config: + common: + scrape_interval: 30s +``` + +You might set `lowDataMode` flag to `true` (it will filter some metrics which can also be collected using New Relic Kubernetes integration), check +`values.yaml` for details. + +It is also possible to adjust how frequently Prometheus scrapes the targets by setting up the` config.common.scrape_interval` value. + + +### Affinities and tolerations + +The New Relic common library allows you to set affinities, tolerations, and node selectors globally using e.g. `.global.affinity` to ease the configuration +when you use this chart using `nri-bundle`. This chart has an extra level of granularity to the components that it deploys: +control plane, ksm, and kubelet. + +Take this snippet as an example: +```yaml +global: + affinity: {} +affinity: {} +``` + +The order to set the affinity is to set `affinity` field (at root level), if that value is empty, the chart fallbacks to `global.affinity`. + +{{ template "chart.valuesSection" . }} + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/Chart.yaml new file mode 100644 index 000000000..b65ac15d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +- name: kang-makes + url: https://github.com/kang-makes +name: common-library +type: library +version: 1.2.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/DEVELOPERS.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/DEVELOPERS.md new file mode 100644 index 000000000..3ccc108e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/DEVELOPERS.md @@ -0,0 +1,663 @@ +# Functions/templates documented for chart writers +Here is some rough documentation separated by the file that contains the function, the function +name and how to use it. We are not covering functions that start with `_` (e.g. +`newrelic.common.license._licenseKey`) because they are used internally by this library for +other helpers. Helm does not have the concept of "public" or "private" functions/templates so +this is a convention of ours. + +## _naming.tpl +These functions are used to name objects. + +### `newrelic.common.naming.name` +This is the same as the idiomatic `CHART-NAME.name` that is created when you use `helm create`. + +It honors `.Values.nameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.name" . }} +``` + +### `newrelic.common.naming.fullname` +This is the same as the idiomatic `CHART-NAME.fullname` that is created when you use `helm create` + +It honors `.Values.fullnameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.fullname" . }} +``` + +### `newrelic.common.naming.chart` +This is the same as the idiomatic `CHART-NAME.chart` that is created when you use `helm create`. + +It is mostly useless for chart writers. It is used internally for templating the labels but there +is no reason to keep it "private". + +Usage: +```mustache +{{ include "newrelic.common.naming.chart" . }} +``` + +### `newrelic.common.naming.truncateToDNS` +This is a useful template that could be used to trim a string to 63 chars and does not end with a dash (`-`). +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $truncatedName := include "newrelic.common.naming.truncateToDNS" $nameToTruncate }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-string-that-should-be */ -}} +``` + +### `newrelic.common.naming.truncateToDNSWithSuffix` +This template function is the same as the above but instead of receiving a string you should give a `dict` +with a `name` and a `suffix`. This function will join them with a dash (`-`) and trim the `name` so the +result of `name-suffix` is no more than 63 chars + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $suffix := "A-NOT-SO-LONG-SUFFIX" }} +{{- $truncatedName := include "truncateToDNSWithSuffix" (dict "name" $nameToTruncate "suffix" $suffix) }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-A-NOT-SO-LONG-SUFFIX */ -}} +``` + + + +## _labels.tpl +### `newrelic.common.labels`, `newrelic.common.labels.selectorLabels` and `newrelic.common.labels.podLabels` +These are functions that are used to label objects. They are configured by this `values.yaml` +```yaml +global: + podLabels: {} # included in all the pods of all the charts that implement this library + labels: {} # included in all the objects of all the charts that implement this library +podLabels: {} # included in all the pods of this chart +labels: {} # included in all the objects of this chart +``` + +label maps are merged from global to local values. + +And chart writer should use them like this: +```mustache +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} +``` + +`newrelic.common.labels.podLabels` includes `newrelic.common.labels.selectorLabels` automatically. + + + +## _priority-class-name.tpl +### `newrelic.common.priorityClassName` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + priorityClassName: "" +priorityClassName: "" +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `priorityClassName` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} +``` + + + +## _hostnetwork.tpl +### `newrelic.common.hostNetwork` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + hostNetwork: # Note that this is empty (nil) +hostNetwork: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `hostNetwork` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.hostNetwork" . }} + hostNetwork: {{ . }} + {{- end }} +``` + +### `newrelic.common.hostNetwork.value` +This function is an abstraction of the function above but this returns directly "true" or "false". + +Be careful with using this with an `if` as Helm does evaluate "false" (string) as `true`. + +Usage (example in a pod spec): +```mustache +spec: + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} +``` + + + +## _dnsconfig.tpl +### `newrelic.common.dnsConfig` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + dnsConfig: {} +dnsConfig: {} +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `dnsConfig` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _images.tpl +These functions help us to deal with how images are templated. This allows setting `registries` +where to fetch images globally while being flexible enough to fit in different maps of images +and deployments with one or more images. This is the example of a complex `values.yaml` that +we are going to use during the documentation of these functions: + +```yaml +global: + images: + registry: nexus-3-instance.internal.clients-domain.tld +jobImage: + registry: # defaults to "example.tld" when empty in these examples + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent + pullSecrets: [] +images: + integration: + registry: + repository: newrelic/nri-kube-events + tag: 1.8.0 + pullPolicy: IfNotPresent + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.22.0 + pullPolicy: IfNotPresent + pullSecrets: [] +``` + +### `newrelic.common.images.image` +This will return a string with the image ready to be downloaded that includes the registry, the image and the tag. +`defaultRegistry` is used to keep `registry` field empty in `values.yaml` so you can override the image using +`global.images.registry`, your local `jobImage.registry` and be able to fallback to a registry that is not `docker.io` +(Or the default repository that the client could have set in the CRI). + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.image" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.registry` +It returns the registry from the global or local values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.registry" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.repository` +It returns the image from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.tag` +It returns the image's tag from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.renderPullSecrets` +If returns a merged map that contains the pull secrets from the global configuration and the local one. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.jobImage.pullSecrets "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +``` + + + +## _serviceaccount.tpl +These functions are used to evaluate if the service account should be created, with which name and add annotations to it. + +The functions that the common library has implemented for service accounts are: +* `newrelic.common.serviceAccount.create` +* `newrelic.common.serviceAccount.name` +* `newrelic.common.serviceAccount.annotations` + +Usage: +```mustache +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +``` + + + +## _affinity.tpl, _nodeselector.tpl and _tolerations.tpl +These three files are almost the same and they follow the idiomatic way of `helm create`. + +Each function also looks if there is a global value like the other helpers. +```yaml +global: + affinity: {} + nodeSelector: {} + tolerations: [] +affinity: {} +nodeSelector: {} +tolerations: [] +``` + +The values here are replaced instead of be merged. If a value at root level is found, the global one is ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _agent-config.tpl +### `newrelic.common.agentConfig.defaults` +This returns a YAML that the agent can use directly as a config that includes other options from the values file like verbose mode, +custom attributes, FedRAMP and such. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include newrelic.common.naming.truncateToDNSWithSuffix (dict "name" (include "newrelic.common.naming.fullname" .) suffix "agent-config") }} + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "newrelic.common.agentConfig.defaults" . | nindent 4 }} +``` + + + +## _cluster.tpl +### `newrelic.common.cluster` +Returns the cluster name + +Usage: +```mustache +{{ include "newrelic.common.cluster" . }} +``` + + + +## _custom-attributes.tpl +### `newrelic.common.customAttributes` +Return custom attributes in YAML format. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + name: example +data: + custom-attributes.yaml: | + {{- include "newrelic.common.customAttributes" . | nindent 4 }} + custom-attributes.json: | + {{- include "newrelic.common.customAttributes" . | fromYaml | toJson | nindent 4 }} +``` + + + +## _fedramp.tpl +### `newrelic.common.fedramp.enabled` +Returns true if FedRAMP is enabled or an empty string if not. It can be safely used in conditionals as an empty string is a Helm falsiness. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled" . }} +``` + +### `newrelic.common.fedramp.enabled.value` +Returns true if FedRAMP is enabled or false if not. This is to have the value of FedRAMP ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled.value" . }} +``` + + + +## _license.tpl +### `newrelic.common.license.secretName` and ### `newrelic.common.license.secretKeyName` +Returns the secret and key inside the secret where to read the license key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the license key. + +To create the secret use `newrelic.common.license.secret`. + +Usage: +```mustache +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + containers: + - name: agent + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} +``` + + + +## _license_secret.tpl +### `newrelic.common.license.secret` +This function templates the secret that is used by agents and integrations with the license Key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any license key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.license.secret" . -}} +``` + + + +## _insights.tpl +### `newrelic.common.insightsKey.secretName` and ### `newrelic.common.insightsKey.secretKeyName` +Returns the secret and key inside the secret where to read the insights key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the insights key. + +To create the secret use `newrelic.common.insightsKey.secret`. + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: statsd +spec: + containers: + - name: statsd + env: + - name: "INSIGHTS_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + key: {{ include "newrelic.common.insightsKey.secretKeyName" . }} +``` + + + +## _insights_secret.tpl +### `newrelic.common.insightsKey.secret` +This function templates the secret that is used by agents and integrations with the insights key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any insights key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.insightsKey.secret" . -}} +``` + + + +## _low-data-mode.tpl +### `newrelic.common.lowDataMode` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + lowDataMode: # Note that this is empty (nil) +lowDataMode: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `lowdataMode` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.lowDataMode" . }} +``` + + + +## _privileged.tpl +### `newrelic.common.privileged` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + privileged: # Note that this is empty (nil) +privileged: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `privileged` is defined, the global one is going to be always ignored. + +Chart writers could override this and put directly a `true` in the `values.yaml` to override the +default of the common library. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.privileged" . }} +``` + +### `newrelic.common.privileged.value` +Returns true if privileged mode is enabled or false if not. This is to have the value of privileged ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.privileged.value" . }} +``` + + + +## _proxy.tpl +### `newrelic.common.proxy` +Returns the proxy URL configured by the user. + +Usage: +```mustache +{{ include "newrelic.common.proxy" . }} +``` + + + +## _security-context.tpl +Use these functions to share the security context among all charts. Useful in clusters that have security enforcing not to +use the root user (like OpenShift) or users that have an admission webhooks. + +The functions are: +* `newrelic.common.securityContext.container` +* `newrelic.common.securityContext.pod` + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + spec: + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + containers: + - name: example + {{- with include "nriKubernetes.securityContext.container" . }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} +``` + + + +## _staging.tpl +### `newrelic.common.nrStaging` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + nrStaging: # Note that this is empty (nil) +nrStaging: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `nrStaging` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging" . }} +``` + +### `newrelic.common.nrStaging.value` +Returns true if staging is enabled or false if not. This is to have the staging value ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging.value" . }} +``` + + + +## _verbose-log.tpl +### `newrelic.common.verboseLog` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + verboseLog: # Note that this is empty (nil) +verboseLog: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `verboseLog` is defined, the global one is going to be always ignored. + +Usage: +```mustache +{{ include "newrelic.common.verboseLog" . }} +``` + +### `newrelic.common.verboseLog.valueAsBoolean` +Returns true if verbose is enabled or false if not. This is to have the verbose value ready to be templated as a boolean + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsBoolean" . }} +``` + +### `newrelic.common.verboseLog.valueAsInt` +Returns 1 if verbose is enabled or 0 if not. This is to have the verbose value ready to be templated as an integer + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsInt" . }} +``` diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/README.md new file mode 100644 index 000000000..10f08ca67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/README.md @@ -0,0 +1,106 @@ +# Helm Common library + +The common library is a way to unify the UX through all the Helm charts that implement it. + +The tooling suite that New Relic is huge and growing and this allows to set things globally +and locally for a single chart. + +## Documentation for chart writers + +If you are writing a chart that is going to use this library you can check the [developers guide](/library/common-library/DEVELOPERS.md) to see all +the functions/templates that we have implemented, what they do and how to use them. + +## Values managed globally + +We want to have a seamless experience through all the charts so we created this library that tries to standardize the behaviour +of all the charts. Sadly, because of the complexity of all these integrations, not all the charts behave exactly as expected. + +An example is `newrelic-infrastructure` that ignores `hostNetwork` in the control plane scraper because most of the users has the +control plane listening in the node to `localhost`. + +For each chart that has a special behavior (or further information of the behavior) there is a "chart particularities" section +in its README.md that explains which is the expected behavior. + +At the time of writing this, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this +library and honors global options as described in this document. + +Here is a list of global options: + +| Global keys | Local keys | Default | Merged[1](#values-managed-globally-1) | Description | +|-------------|------------|---------|--------------------------------------------------|-------------| +| global.cluster | cluster | `""` | | Name of the Kubernetes cluster monitored | +| global.licenseKey | licenseKey | `""` | | This set this license key to use | +| global.customSecretName | customSecretName | `""` | | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there | +| global.customSecretLicenseKey | customSecretLicenseKey | `""` | | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located | +| global.podLabels | podLabels | `{}` | yes | Additional labels for chart pods | +| global.labels | labels | `{}` | yes | Additional labels for chart objects | +| global.priorityClassName | priorityClassName | `""` | | Sets pod's priorityClassName | +| global.hostNetwork | hostNetwork | `false` | | Sets pod's hostNetwork | +| global.dnsConfig | dnsConfig | `{}` | | Sets pod's dnsConfig | +| global.images.registry | See [Further information](#values-managed-globally-2) | `""` | | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.images.pullSecrets | See [Further information](#values-managed-globally-2) | `[]` | yes | Set secrets to be able to fetch images | +| global.podSecurityContext | podSecurityContext | `{}` | | Sets security context (at pod level) | +| global.containerSecurityContext | containerSecurityContext | `{}` | | Sets security context (at container level) | +| global.affinity | affinity | `{}` | | Sets pod/node affinities | +| global.nodeSelector | nodeSelector | `{}` | | Sets pod's node selector | +| global.tolerations | tolerations | `[]` | | Sets pod's tolerations to node taints | +| global.serviceAccount.create | serviceAccount.create | `true` | | Configures if the service account should be created or not | +| global.serviceAccount.name | serviceAccount.name | name of the release | | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. | +| global.serviceAccount.annotations | serviceAccount.annotations | `{}` | yes | Add these annotations to the service account we create | +| global.customAttributes | customAttributes | `{}` | | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.fedramp | fedramp | `false` | | Enables FedRAMP | +| global.lowDataMode | lowDataMode | `false` | | Reduces number of metrics sent in order to reduce costs | +| global.privileged | privileged | Depends on the chart | | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | +| global.proxy | proxy | `""` | | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.nrStaging | nrStaging | `false` | | Send the metrics to the staging backend. Requires a valid staging license key | +| global.verboseLog | verboseLog | `false` | | Sets the debug/trace logs to this integration or all integrations if it is set globally | + +### Further information + +#### 1. Merged + +Merged means that the values from global are not replaced by the local ones. Think in this example: +```yaml +global: + labels: + global: global + hostNetwork: true + nodeSelector: + global: global + +labels: + local: local +nodeSelector: + local: local +hostNetwork: false +``` + +This values will template `hostNetwork` to `false`, a map of labels `{ "global": "global", "local": "local" }` and a `nodeSelector` with +`{ "local": "local" }`. + +As Helm by default merges all the maps it could be confusing that we have two behaviors (merging `labels` and replacing `nodeSelector`) +the `values` from global to local. This is the rationale behind this: +* `hostNetwork` is templated to `false` because is overriding the value defined globally. +* `labels` are merged because the user may want to label all the New Relic pods at once and label other solution pods differently for + clarity' sake. +* `nodeSelector` does not merge as `labels` because could make it harder to overwrite/delete a selector that comes from global because + of the logic that Helm follows merging maps. + + +#### 2. Fine grain registries + +Some charts only have 1 image while others that can have 2 or more images. The local path for the registry can change depending +on the chart itself. + +As this is mostly unique per helm chart, you should take a look to the chart's values table (or directly to the `values.yaml` file to see all the +images that you can change. + +This should only be needed if you have an advanced setup that forces you to have granularity enough to force a proxy/cache registry per integration. + + + +#### 3. Privileged mode + +By default, from the common library, the privileged mode is set to false. But most of the helm charts require this to be true to fetch more +metrics so could see a true in some charts. The consequences of the privileged mode differ from one chart to another so for each chart that +honors the privileged mode toggle should be a section in the README explaining which is the behavior with it enabled or disabled. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_affinity.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_affinity.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod affinity */ -}} +{{- define "newrelic.common.affinity" -}} + {{- if .Values.affinity -}} + {{- toYaml .Values.affinity -}} + {{- else if .Values.global -}} + {{- if .Values.global.affinity -}} + {{- toYaml .Values.global.affinity -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_agent-config.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..9c32861a0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,26 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +log: + level: trace +{{- end }} + +{{- if (include "newrelic.common.nrStaging" . ) }} +staging: true +{{- end }} + +{{- with include "newrelic.common.proxy" . }} +proxy: {{ . | quote }} +{{- end }} + +{{- with include "newrelic.common.fedramp.enabled" . }} +fedramp: {{ . }} +{{- end }} + +{{- with fromYaml ( include "newrelic.common.customAttributes" . ) }} +custom_attributes: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_cluster.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_cluster.tpl @@ -0,0 +1,15 @@ +{{/* +Return the cluster +*/}} +{{- define "newrelic.common.cluster" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.cluster -}} + {{- .Values.cluster -}} +{{- else if $global.cluster -}} + {{- $global.cluster -}} +{{- else -}} + {{ fail "There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required." }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_custom-attributes.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_custom-attributes.tpl @@ -0,0 +1,17 @@ +{{/* +This will render custom attributes as a YAML ready to be templated or be used with `fromYaml`. +*/}} +{{- define "newrelic.common.customAttributes" -}} +{{- $customAttributes := dict -}} + +{{- $global := index .Values "global" | default dict -}} +{{- if $global.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes $global.customAttributes -}} +{{- end -}} + +{{- if .Values.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes .Values.customAttributes -}} +{{- end -}} + +{{- toYaml $customAttributes -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_dnsconfig.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_dnsconfig.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod dnsConfig */ -}} +{{- define "newrelic.common.dnsConfig" -}} + {{- if .Values.dnsConfig -}} + {{- toYaml .Values.dnsConfig -}} + {{- else if .Values.global -}} + {{- if .Values.global.dnsConfig -}} + {{- toYaml .Values.global.dnsConfig -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_fedramp.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_fedramp.tpl @@ -0,0 +1,25 @@ +{{- /* Defines the fedRAMP flag */ -}} +{{- define "newrelic.common.fedramp.enabled" -}} + {{- if .Values.fedramp -}} + {{- if .Values.fedramp.enabled -}} + {{- .Values.fedramp.enabled -}} + {{- end -}} + {{- else if .Values.global -}} + {{- if .Values.global.fedramp -}} + {{- if .Values.global.fedramp.enabled -}} + {{- .Values.global.fedramp.enabled -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{- /* Return FedRAMP value directly ready to be templated */ -}} +{{- define "newrelic.common.fedramp.enabled.value" -}} +{{- if include "newrelic.common.fedramp.enabled" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_hostnetwork.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_hostnetwork.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the hostNetwork toggle. +This helper allows to override the global `.global.hostNetwork` with the value of `.hostNetwork`. +Returns "true" if `hostNetwork` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.hostNetwork" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- /* +`get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs + +We also want only to return when this is true, returning `false` here will template "false" (string) when doing +an `(include "newrelic.common.hostNetwork" .)`, which is not an "empty string" so it is `true` if it is used +as an evaluation somewhere else. +*/ -}} +{{- if get .Values "hostNetwork" | kindIs "bool" -}} + {{- if .Values.hostNetwork -}} + {{- .Values.hostNetwork -}} + {{- end -}} +{{- else if get $global "hostNetwork" | kindIs "bool" -}} + {{- if $global.hostNetwork -}} + {{- $global.hostNetwork -}} + {{- end -}} +{{- end -}} +{{- end -}} + + +{{- /* +Abstraction of the hostNetwork toggle. +This helper abstracts the function "newrelic.common.hostNetwork" to return true or false directly. +*/ -}} +{{- define "newrelic.common.hostNetwork.value" -}} +{{- if include "newrelic.common.hostNetwork" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_images.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..d4fb43290 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_images.tpl @@ -0,0 +1,94 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "defaultRegistry" .defaultRegistry "context" .context ) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic.common.images.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image registry +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} +{{- $globalRegistry := "" -}} +{{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- with .context.Values.global.images.registry -}} + {{- $globalRegistry = . -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- $localRegistry := "" -}} +{{- if .imageRoot.registry -}} + {{- $localRegistry = .imageRoot.registry -}} +{{- end -}} + +{{- $registry := $localRegistry | default $globalRegistry | default .defaultRegistry -}} +{{- if $registry -}} + {{- $registry -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image repository +{{ include "newrelic.common.images.repository" .Values.path.to.the.image }} +*/ -}} +{{- define "newrelic.common.images.repository" -}} + {{- .repository -}} +{{- end -}} + + + +{{- /* +Return the proper image tag +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.tag" -}} + {{- .imageRoot.tag | default .context.Chart.AppVersion | toString -}} +{{- end -}} + + + +{{- /* +Return the proper Image Pull Registry Secret Names evaluating values as templates +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.path.to.the.images.pullSecrets1, .Values.path.to.the.images.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- if .context.Values.global.images.pullSecrets -}} + {{- range .context.Values.global.images.pullSecrets -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- range .pullSecrets -}} + {{- if not (empty .) -}} + {{- range . -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if $flatlist -}} + {{- toYaml $flatlist -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_insights.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_insights.tpl new file mode 100644 index 000000000..895c37732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_insights.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the Insights Key. +*/}} +{{- define "newrelic.common.insightsKey.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "insightskey" ) -}} +{{- include "newrelic.common.insightsKey._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +*/}} +{{- define "newrelic.common.insightsKey.secretKeyName" -}} +{{- include "newrelic.common.insightsKey._customSecretKey" . | default "insightsKey" -}} +{{- end -}} + +{{/* +Return local insightsKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._licenseKey" -}} +{{- if .Values.insightsKey -}} + {{- .Values.insightsKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.insightsKey -}} + {{- .Values.global.insightsKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the Insights Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretName" -}} +{{- if .Values.customInsightsKeySecretName -}} + {{- .Values.customInsightsKeySecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretName -}} + {{- .Values.global.customInsightsKeySecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretKey" -}} +{{- if .Values.customInsightsKeySecretKey -}} + {{- .Values.customInsightsKeySecretKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretKey }} + {{- .Values.global.customInsightsKeySecretKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_insights_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_insights_secret.yaml.tpl new file mode 100644 index 000000000..556caa6ca --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_insights_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the insights key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.insightsKey.secret" }} +{{- if not (include "newrelic.common.insightsKey._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.insightsKey._licenseKey" .) }} + {{- fail "You must specify a insightsKey or a customInsightsSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.insightsKey.secretKeyName" . }}: {{ include "newrelic.common.insightsKey._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_labels.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_labels.tpl @@ -0,0 +1,54 @@ +{{/* +This will render the labels that should be used in all the manifests used by the helm chart. +*/}} +{{- define "newrelic.common.labels" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- $chart := dict "helm.sh/chart" (include "newrelic.common.naming.chart" . ) -}} +{{- $managedBy := dict "app.kubernetes.io/managed-by" .Release.Service -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $labels := mustMergeOverwrite $chart $managedBy $selectorLabels -}} +{{- if .Chart.AppVersion -}} +{{- $labels = mustMergeOverwrite $labels (dict "app.kubernetes.io/version" .Chart.AppVersion) -}} +{{- end -}} + +{{- $globalUserLabels := $global.labels | default dict -}} +{{- $localUserLabels := .Values.labels | default dict -}} + +{{- $labels = mustMergeOverwrite $labels $globalUserLabels $localUserLabels -}} + +{{- toYaml $labels -}} +{{- end -}} + + + +{{/* +This will render the labels that should be used in deployments/daemonsets template pods as a selector. +*/}} +{{- define "newrelic.common.labels.selectorLabels" -}} +{{- $name := dict "app.kubernetes.io/name" ( include "newrelic.common.naming.name" . ) -}} +{{- $instance := dict "app.kubernetes.io/instance" .Release.Name -}} + +{{- $selectorLabels := mustMergeOverwrite $name $instance -}} + +{{- toYaml $selectorLabels -}} +{{- end }} + + + +{{/* +Pod labels +*/}} +{{- define "newrelic.common.labels.podLabels" -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $global := index .Values "global" | default dict -}} +{{- $globalPodLabels := $global.podLabels | default dict }} + +{{- $localPodLabels := .Values.podLabels | default dict }} + +{{- $podLabels := mustMergeOverwrite $selectorLabels $globalPodLabels $localPodLabels -}} + +{{- toYaml $podLabels -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_license.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..647b4ff43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_license.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "license" ) -}} +{{- include "newrelic.common.license._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +*/}} +{{- define "newrelic.common.license.secretKeyName" -}} +{{- include "newrelic.common.license._customSecretKey" . | default "licenseKey" -}} +{{- end -}} + +{{/* +Return local licenseKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._licenseKey" -}} +{{- if .Values.licenseKey -}} + {{- .Values.licenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.licenseKey -}} + {{- .Values.global.licenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the License Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretName" -}} +{{- if .Values.customSecretName -}} + {{- .Values.customSecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretName -}} + {{- .Values.global.customSecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretKey" -}} +{{- if .Values.customSecretLicenseKey -}} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_license_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_license_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the license key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.license.secret" }} +{{- if not (include "newrelic.common.license._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.license._licenseKey" .) }} + {{- fail "You must specify a licenseKey or a customSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.license.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.license.secretKeyName" . }}: {{ include "newrelic.common.license._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_low-data-mode.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_low-data-mode.tpl @@ -0,0 +1,26 @@ +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..19fa92648 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_naming.tpl @@ -0,0 +1,73 @@ +{{/* +This is an function to be called directly with a string just to truncate strings to +63 chars because some Kubernetes name fields are limited to that. +*/}} +{{- define "newrelic.common.naming.truncateToDNS" -}} +{{- . | trunc 63 | trimSuffix "-" }} +{{- end }} + + + +{{- /* +Given a name and a suffix returns a 'DNS Valid' which always include the suffix, truncating the name if needed. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If suffix is too long it gets truncated but it always takes precedence over name, so a 63 chars suffix would suppress the name. +Usage: +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "" "suffix" "my-suffix" ) }} +*/ -}} +{{- define "newrelic.common.naming.truncateToDNSWithSuffix" -}} +{{- $suffix := (include "newrelic.common.naming.truncateToDNS" .suffix) -}} +{{- $maxLen := (max (sub 63 (add1 (len $suffix))) 0) -}} {{- /* We prepend "-" to the suffix so an additional character is needed */ -}} + +{{- $newName := .name | trunc ($maxLen | int) | trimSuffix "-" -}} +{{- if $newName -}} +{{- printf "%s-%s" $newName $suffix -}} +{{- else -}} +{{ $suffix }} +{{- end -}} + +{{- end -}} + + + +{{/* +Expand the name of the chart. +Uses the Chart name by default if nameOverride is not set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.name" -}} +{{- $name := .Values.nameOverride | default .Chart.Name -}} +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end }} + + + +{{/* +Create a default fully qualified app name. +By default the full name will be "" just in if it has the chart name included in that, if not +it will be concatenated like "-". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.fullname" -}} +{{- $name := include "newrelic.common.naming.name" . -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} + +{{- end -}} + + + +{{/* +Create chart name and version as used by the chart label. +This function should not be used for naming objects. Use "common.naming.{name,fullname}" instead. +*/}} +{{- define "newrelic.common.naming.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_nodeselector.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_nodeselector.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod nodeSelector */ -}} +{{- define "newrelic.common.nodeSelector" -}} + {{- if .Values.nodeSelector -}} + {{- toYaml .Values.nodeSelector -}} + {{- else if .Values.global -}} + {{- if .Values.global.nodeSelector -}} + {{- toYaml .Values.global.nodeSelector -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_priority-class-name.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_priority-class-name.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the pod priorityClassName */ -}} +{{- define "newrelic.common.priorityClassName" -}} + {{- if .Values.priorityClassName -}} + {{- .Values.priorityClassName -}} + {{- else if .Values.global -}} + {{- if .Values.global.priorityClassName -}} + {{- .Values.global.priorityClassName -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_privileged.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_privileged.tpl @@ -0,0 +1,28 @@ +{{- /* +This is a helper that returns whether the chart should assume the user is fine deploying privileged pods. +*/ -}} +{{- define "newrelic.common.privileged" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists. */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values "privileged" | kindIs "bool" -}} + {{- if .Values.privileged -}} + {{- .Values.privileged -}} + {{- end -}} +{{- else if get $global "privileged" | kindIs "bool" -}} + {{- if $global.privileged -}} + {{- $global.privileged -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* Return directly "true" or "false" based in the exist of "newrelic.common.privileged" */ -}} +{{- define "newrelic.common.privileged.value" -}} +{{- if include "newrelic.common.privileged" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_proxy.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_proxy.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the proxy */ -}} +{{- define "newrelic.common.proxy" -}} + {{- if .Values.proxy -}} + {{- .Values.proxy -}} + {{- else if .Values.global -}} + {{- if .Values.global.proxy -}} + {{- .Values.global.proxy -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_security-context.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_security-context.tpl @@ -0,0 +1,23 @@ +{{- /* Defines the container securityContext context */ -}} +{{- define "newrelic.common.securityContext.container" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.containerSecurityContext -}} + {{- toYaml .Values.containerSecurityContext -}} +{{- else if $global.containerSecurityContext -}} + {{- toYaml $global.containerSecurityContext -}} +{{- end -}} +{{- end -}} + + + +{{- /* Defines the pod securityContext context */ -}} +{{- define "newrelic.common.securityContext.pod" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.podSecurityContext -}} + {{- toYaml .Values.podSecurityContext -}} +{{- else if $global.podSecurityContext -}} + {{- toYaml $global.podSecurityContext -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_serviceaccount.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..2d352f6ea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_serviceaccount.tpl @@ -0,0 +1,90 @@ +{{- /* Defines if the service account has to be created or not */ -}} +{{- define "newrelic.common.serviceAccount.create" -}} +{{- $valueFound := false -}} + +{{- /* Look for a global creation of a service account */ -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "create" | kindIs "bool") -}} + {{- $valueFound = true -}} + {{- if .Values.serviceAccount.create -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.serviceAccount.name" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.serviceAccount.create -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Look for a local creation of a service account */ -}} +{{- if not $valueFound -}} + {{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} + {{- $global := index .Values "global" | default dict -}} + {{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "create" | kindIs "bool" -}} + {{- $valueFound = true -}} + {{- if $global.serviceAccount.create -}} + {{- $global.serviceAccount.create -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* In case no serviceAccount value has been found, default to "true" */ -}} +{{- if not $valueFound -}} +true +{{- end -}} +{{- end -}} + + + +{{- /* Defines the name of the service account */ -}} +{{- define "newrelic.common.serviceAccount.name" -}} +{{- $localServiceAccount := "" -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "name" | kindIs "string") -}} + {{- $localServiceAccount = .Values.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := "" -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "name" | kindIs "string" -}} + {{- $globalServiceAccount = $global.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- if (include "newrelic.common.serviceAccount.create" .) -}} + {{- $localServiceAccount | default $globalServiceAccount | default (include "newrelic.common.naming.fullname" .) -}} +{{- else -}} + {{- $localServiceAccount | default $globalServiceAccount | default "default" -}} +{{- end -}} +{{- end -}} + + + +{{- /* Merge the global and local annotations for the service account */ -}} +{{- define "newrelic.common.serviceAccount.annotations" -}} +{{- $localServiceAccount := dict -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if get .Values.serviceAccount "annotations" -}} + {{- $localServiceAccount = .Values.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := dict -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "annotations" -}} + {{- $globalServiceAccount = $global.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $merged := mustMergeOverwrite $globalServiceAccount $localServiceAccount -}} + +{{- if $merged -}} + {{- toYaml $merged -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_staging.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_staging.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the nrStaging toggle. +This helper allows to override the global `.global.nrStaging` with the value of `.nrStaging`. +Returns "true" if `nrStaging` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.nrStaging" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "nrStaging" | kindIs "bool") -}} + {{- if .Values.nrStaging -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.nrStaging" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.nrStaging -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "nrStaging" | kindIs "bool" -}} + {{- if $global.nrStaging -}} + {{- $global.nrStaging -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Returns "true" of "false" directly instead of empty string (Helm falsiness) based on the exit of "newrelic.common.nrStaging" +*/ -}} +{{- define "newrelic.common.nrStaging.value" -}} +{{- if include "newrelic.common.nrStaging" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_tolerations.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_tolerations.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod tolerations */ -}} +{{- define "newrelic.common.tolerations" -}} + {{- if .Values.tolerations -}} + {{- toYaml .Values.tolerations -}} + {{- else if .Values.global -}} + {{- if .Values.global.tolerations -}} + {{- toYaml .Values.global.tolerations -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_verbose-log.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/templates/_verbose-log.tpl @@ -0,0 +1,54 @@ +{{- /* +Abstraction of the verbose toggle. +This helper allows to override the global `.global.verboseLog` with the value of `.verboseLog`. +Returns "true" if `verbose` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.verboseLog" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "verboseLog" | kindIs "bool") -}} + {{- if .Values.verboseLog -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.verboseLog" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.verboseLog -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "verboseLog" | kindIs "bool" -}} + {{- if $global.verboseLog -}} + {{- $global.verboseLog -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return true or false directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsBoolean" -}} +{{- if include "newrelic.common.verboseLog" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return 1 or 0 directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsInt" -}} +{{- if include "newrelic.common.verboseLog" . -}} +1 +{{- else -}} +0 +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/charts/common-library/values.yaml @@ -0,0 +1 @@ +# values are not needed for the library chart, however this file is still needed for helm lint to work. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/ci/test-values.yaml new file mode 100644 index 000000000..ac5ed6bb0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/ci/test-values.yaml @@ -0,0 +1,6 @@ +licenseKey: fakeLicenseKey +cluster: test-cluster-name +images: + configurator: + repository: ct/prometheus-configurator + tag: ct diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/static/lowdatamodedefaults.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/static/lowdatamodedefaults.yaml new file mode 100644 index 000000000..726815755 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/static/lowdatamodedefaults.yaml @@ -0,0 +1,6 @@ +# This file contains an entry of the array `extra_write_relabel_configs` to filter +# metrics on Low Data Mode. These metrics are already collected by the New Relic Kubernetes Integration. +low_data_mode: +- action: drop + source_labels: [__name__] + regex: "kube_.+|container_.+|machine_.+|cadvisor_.+" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/static/metrictyperelabeldefaults.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/static/metrictyperelabeldefaults.yaml new file mode 100644 index 000000000..c0a277409 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/static/metrictyperelabeldefaults.yaml @@ -0,0 +1,17 @@ +# This file contains an entry of the array `extra_write_relabel_configs` to override metric types. +# https://docs.newrelic.com/docs/infrastructure/prometheus-integrations/install-configure-remote-write/set-your-prometheus-remote-write-integration#override-mapping +metrics_type_relabel: +- source_labels: [__name__] + separator: ; + regex: timeseries_write_(.*) # Cockroach + target_label: newrelic_metric_type + replacement: counter + action: replace +- source_labels: [__name__] + separator: ; + regex: sql_byte(.*) # Cockroach + target_label: newrelic_metric_type + replacement: counter + action: replace +# Note that adding more elements to this list could cause a possible breaking change to users already leveraging affected metrics. +# Therefore, before adding new entries check if any users is relying already on those metrics and warn them. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/_helpers.tpl new file mode 100644 index 000000000..6cc58e251 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/_helpers.tpl @@ -0,0 +1,165 @@ +{{- /* Return the newrelic-prometheus configuration */ -}} + +{{- /* it builds the common configuration from configurator config, cluster name and custom attributes */ -}} +{{- define "newrelic-prometheus.configurator.common" -}} +{{- $tmp := dict "external_labels" (dict "cluster_name" (include "newrelic.common.cluster" . )) -}} + +{{- if .Values.config -}} + {{- if .Values.config.common -}} + {{- $_ := mustMerge $tmp .Values.config.common -}} + {{- end -}} +{{- end -}} + +{{- $tmpCustomAttribute := dict "external_labels" (include "newrelic.common.customAttributes" . | fromYaml ) -}} +{{- $tmp = mustMerge $tmp $tmpCustomAttribute -}} + +common: +{{- $tmp | toYaml | nindent 2 -}} + +{{- end -}} + + +{{- /* it builds the newrelic_remote_write configuration from configurator config */ -}} +{{- define "newrelic-prometheus.configurator.newrelic_remote_write" -}} +{{- $tmp := dict -}} + +{{- if include "newrelic.common.nrStaging" . -}} + {{- $_ := set $tmp "staging" true -}} +{{- end -}} + +{{- if include "newrelic.common.fedramp.enabled" . -}} + {{- $_ := set $tmp "fedramp" (dict "enabled" true) -}} +{{- end -}} + +{{- $extra_write_relabel_configs :=(include "newrelic-prometheus.configurator.extra_write_relabel_configs" . | fromYaml) -}} +{{- if ne (len $extra_write_relabel_configs.list) 0 -}} + {{- $_ := set $tmp "extra_write_relabel_configs" $extra_write_relabel_configs.list -}} +{{- end -}} + +{{- if .Values.config -}} +{{- if .Values.config.newrelic_remote_write -}} + {{- $tmp = mustMerge $tmp .Values.config.newrelic_remote_write -}} +{{- end -}} +{{- end -}} + +{{- if not (empty $tmp) -}} + {{- dict "newrelic_remote_write" $tmp | toYaml -}} +{{- end -}} + +{{- end -}} + +{{- /* it builds the extra_write_relabel_configs configuration merging: lowdatamode, user ones, and metrictyperelabeldefaults */ -}} +{{- define "newrelic-prometheus.configurator.extra_write_relabel_configs" -}} + +{{- $extra_write_relabel_configs := list -}} +{{- if (include "newrelic.common.lowDataMode" .) -}} + {{- $lowDataModeRelabelConfig := .Files.Get "static/lowdatamodedefaults.yaml" | fromYaml -}} + {{- $extra_write_relabel_configs = concat $extra_write_relabel_configs $lowDataModeRelabelConfig.low_data_mode -}} +{{- end -}} + +{{- if .Values.metric_type_override -}} + {{- if .Values.metric_type_override.enabled -}} + {{- $metricTypeOverride := .Files.Get "static/metrictyperelabeldefaults.yaml" | fromYaml -}} + {{- $extra_write_relabel_configs = concat $extra_write_relabel_configs $metricTypeOverride.metrics_type_relabel -}} + {{- end -}} +{{- end -}} + +{{- if .Values.config -}} +{{- if .Values.config.newrelic_remote_write -}} + {{- /* it concatenates the defined 'extra_write_relabel_configs' to the ones defined in lowDataMode */ -}} + {{- if .Values.config.newrelic_remote_write.extra_write_relabel_configs -}} + {{- $extra_write_relabel_configs = concat $extra_write_relabel_configs .Values.config.newrelic_remote_write.extra_write_relabel_configs -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{- /* sadly in helm we cannot pass back a list without putting it into a tmp dict */ -}} +{{ dict "list" $extra_write_relabel_configs | toYaml}} + +{{- end -}} + + +{{- /* it builds the extra_remote_write configuration from configurator config */ -}} +{{- define "newrelic-prometheus.configurator.extra_remote_write" -}} +{{- if .Values.config -}} + {{- if .Values.config.extra_remote_write -}} +extra_remote_write: + {{- .Values.config.extra_remote_write | toYaml | nindent 2 -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-prometheus.configurator.static_targets" -}} +{{- if .Values.config -}} + {{- if .Values.config.static_targets -}} +static_targets: + {{- .Values.config.static_targets | toYaml | nindent 2 -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-prometheus.configurator.extra_scrape_configs" -}} +{{- if .Values.config -}} + {{- if .Values.config.extra_scrape_configs -}} +extra_scrape_configs: + {{- .Values.config.extra_scrape_configs | toYaml | nindent 2 -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-prometheus.configurator.kubernetes" -}} +{{- if .Values.config -}} +{{- if .Values.config.kubernetes -}} +kubernetes: + {{- if .Values.config.kubernetes.jobs }} + jobs: + {{- .Values.config.kubernetes.jobs | toYaml | nindent 2 -}} + {{- end -}} + + {{- if .Values.config.kubernetes.integrations_filter }} + integrations_filter: + {{- .Values.config.kubernetes.integrations_filter | toYaml | nindent 4 -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{- define "newrelic-prometheus.configurator.sharding" -}} + {{- if .Values.sharding -}} +sharding: + total_shards_count: {{ include "newrelic-prometheus.configurator.replicas" . }} + {{- end -}} +{{- end -}} + +{{- define "newrelic-prometheus.configurator.replicas" -}} + {{- if .Values.sharding -}} +{{- .Values.sharding.total_shards_count | default 1 }} + {{- else -}} +1 + {{- end -}} +{{- end -}} + +{{- /* +Return the proper configurator image name +{{ include "newrelic-prometheus.configurator.images.configurator_image" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic-prometheus.configurator.configurator_image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "context" .context) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic-prometheus.configurator.configurator_image.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + +{{- /* +Return the proper image tag for the configurator image +{{ include "newrelic-prometheus.configurator.configurator_image.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic-prometheus.configurator.configurator_image.tag" -}} + {{- .imageRoot.tag | default .context.Chart.Annotations.configuratorVersion | toString -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/clusterrole.yaml new file mode 100644 index 000000000..e9d4208e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/clusterrole.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - endpoints + - services + - pods + - services + verbs: + - get + - list + - watch + - nonResourceURLs: + - "/metrics" + verbs: + - get +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..44244653f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic.common.naming.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/configmap.yaml new file mode 100644 index 000000000..b775aca74 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/configmap.yaml @@ -0,0 +1,31 @@ +kind: ConfigMap +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +apiVersion: v1 +data: + config.yaml: |- + # Configuration for newrelic-prometheus-configurator + {{- with (include "newrelic-prometheus.configurator.newrelic_remote_write" . ) -}} + {{- . | nindent 4 }} + {{- end -}} + {{- with (include "newrelic-prometheus.configurator.extra_remote_write" . ) -}} + {{- . | nindent 4 }} + {{- end -}} + {{- with (include "newrelic-prometheus.configurator.static_targets" . ) -}} + {{- . | nindent 4 }} + {{- end -}} + {{- with (include "newrelic-prometheus.configurator.extra_scrape_configs" . ) -}} + {{- . | nindent 4 }} + {{- end -}} + {{- with (include "newrelic-prometheus.configurator.common" . ) -}} + {{- . | nindent 4 }} + {{- end -}} + {{- with (include "newrelic-prometheus.configurator.kubernetes" . ) -}} + {{- . | nindent 4 }} + {{- end -}} + {{- with (include "newrelic-prometheus.configurator.sharding" . ) -}} + {{- . | nindent 4 }} + {{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/secret.yaml new file mode 100644 index 000000000..f558ee86c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/secret.yaml @@ -0,0 +1,2 @@ +{{- /* Common library will take care of creating the secret or not. */}} +{{- include "newrelic.common.license.secret" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/serviceaccount.yaml new file mode 100644 index 000000000..b1e74523e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- if include "newrelic.common.serviceAccount.annotations" . }} + annotations: + {{- include "newrelic.common.serviceAccount.annotations" . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/statefulset.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/statefulset.yaml new file mode 100644 index 000000000..846c41c23 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/templates/statefulset.yaml @@ -0,0 +1,157 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + serviceName: {{ include "newrelic.common.naming.fullname" . }}-headless + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + replicas: {{ include "newrelic-prometheus.configurator.replicas" . }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.images.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} + {{- if include "newrelic.common.hostNetwork" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- end }} + + serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} + + initContainers: + - name: configurator + {{- with include "newrelic.common.securityContext.container" . }} + securityContext: + {{- . | nindent 12 }} + {{- end }} + image: {{ include "newrelic-prometheus.configurator.configurator_image" ( dict "imageRoot" .Values.images.configurator "context" .) }} + imagePullPolicy: {{ .Values.images.configurator.pullPolicy }} + args: + - --input=/etc/configurator/config.yaml + - --output=/etc/prometheus/config/config.yaml + {{- if include "newrelic.common.verboseLog" . }} + - --verbose=true + {{- end }} + {{- with .Values.resources.configurator }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: configurator-config + mountPath: /etc/configurator/ + - name: prometheus-config + mountPath: /etc/prometheus/config + env: + - name: NR_PROM_DATA_SOURCE_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NR_PROM_LICENSE_KEY + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} + - name: NR_PROM_CHART_VERSION + value: {{ .Chart.Version }} + + containers: + - name: prometheus + {{- with include "newrelic.common.securityContext.container" . }} + securityContext: + {{- . | nindent 12 }} + {{- end }} + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.prometheus "context" .) }} + imagePullPolicy: {{ .Values.images.prometheus.pullPolicy }} + ports: + - containerPort: 9090 + protocol: TCP + livenessProbe: + httpGet: + path: /-/healthy + port: 9090 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 15 + timeoutSeconds: 10 + failureThreshold: 3 + successThreshold: 1 + readinessProbe: + httpGet: + path: /-/ready + port: 9090 + scheme: HTTP + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 4 + failureThreshold: 3 + successThreshold: 1 + args: + - --config.file=/etc/prometheus/config/config.yaml + - --enable-feature=agent,expand-external-labels + - --storage.agent.retention.max-time=30m + - --storage.agent.wal-truncate-frequency=30m + - --storage.agent.path=/etc/prometheus/storage + {{- if include "newrelic.common.verboseLog" . }} + - --log.level=debug + {{- end }} + {{- with .Values.resources.prometheus }} + resources: {{ toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: prometheus-config + mountPath: /etc/prometheus/config + - name: prometheus-storage + mountPath: /etc/prometheus/storage + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + + volumes: + - name: configurator-config + configMap: + name: {{ include "newrelic.common.naming.fullname" . }} + - name: prometheus-config + emptyDir: {} + - name: prometheus-storage + emptyDir: {} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/configmap_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/configmap_test.yaml new file mode 100644 index 000000000..f2dd0468e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/configmap_test.yaml @@ -0,0 +1,572 @@ +suite: test configmap +templates: + - templates/configmap.yaml +tests: + - it: config with defaults + set: + licenseKey: license-key-test + cluster: cluster-test + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + newrelic_remote_write: + extra_write_relabel_configs: + - action: replace + regex: timeseries_write_(.*) + replacement: counter + separator: ; + source_labels: + - __name__ + target_label: newrelic_metric_type + - action: replace + regex: sql_byte(.*) + replacement: counter + separator: ; + source_labels: + - __name__ + target_label: newrelic_metric_type + static_targets: + jobs: + - extra_metric_relabel_config: + - action: keep + regex: prometheus_agent_active_series|prometheus_target_interval_length_seconds|prometheus_target_scrape_pool_targets|prometheus_remote_storage_samples_pending|prometheus_remote_storage_samples_in_total|prometheus_remote_storage_samples_retried_total|prometheus_agent_corruptions_total|prometheus_remote_storage_shards|prometheus_sd_kubernetes_events_total|prometheus_agent_checkpoint_creations_failed_total|prometheus_agent_checkpoint_deletions_failed_total|prometheus_remote_storage_samples_dropped_total|prometheus_remote_storage_samples_failed_total|prometheus_sd_kubernetes_http_request_total|prometheus_agent_truncate_duration_seconds_sum|prometheus_build_info|process_resident_memory_bytes|process_virtual_memory_bytes|process_cpu_seconds_total|prometheus_remote_storage_bytes_total + source_labels: + - __name__ + job_name: self-metrics + skip_sharding: true + targets: + - localhost:9090 + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + kubernetes: + jobs: + - job_name_prefix: default + target_discovery: + endpoints: true + filter: + annotations: + prometheus.io/scrape: true + pod: true + - integrations_filter: + enabled: false + job_name_prefix: newrelic + target_discovery: + endpoints: true + filter: + annotations: + newrelic.io/scrape: true + pod: true + integrations_filter: + app_values: + - redis + - traefik + - calico + - nginx + - coredns + - kube-dns + - etcd + - cockroachdb + - velero + - harbor + - argocd + enabled: true + source_labels: + - app.kubernetes.io/name + - app.newrelic.io/name + - k8s-app + + - it: staging is enabled + set: + licenseKey: license-key-test + cluster: cluster-test + nrStaging: true + metric_type_override: + enabled: false + config: + static_targets: # Set empty to make this test simple + asserts: + - matchRegex: + path: data["config.yaml"] + pattern: "newrelic_remote_write:\n staging: true" # We do not want to test the whole YAML + + - it: fedramp is enabled + set: + licenseKey: license-key-test + cluster: cluster-test + fedramp: + enabled: true + metric_type_override: + enabled: false + config: + static_targets: # Set empty to make this test simple + asserts: + - matchRegex: + path: data["config.yaml"] + pattern: "newrelic_remote_write:\n fedramp:\n enabled: true" # We do not want to test the whole YAML + + - it: config including remote_write most possible sections + set: + licenseKey: license-key-test + cluster: cluster-test + nrStaging: true + config: + newrelic_remote_write: + proxy_url: http://proxy.url + remote_timeout: 30s + tls_config: + insecure_skip_verify: true + queue_config: + retry_on_http_429: false + extra_write_relabel_configs: + - source_labels: + - __name__ + - instance + regex: node_memory_active_bytes;localhost:9100 + action: drop + extra_remote_write: + - url: "https://second.remote.write" + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + newrelic_remote_write: + extra_write_relabel_configs: + - action: replace + regex: timeseries_write_(.*) + replacement: counter + separator: ; + source_labels: + - __name__ + target_label: newrelic_metric_type + - action: replace + regex: sql_byte(.*) + replacement: counter + separator: ; + source_labels: + - __name__ + target_label: newrelic_metric_type + - action: drop + regex: node_memory_active_bytes;localhost:9100 + source_labels: + - __name__ + - instance + proxy_url: http://proxy.url + queue_config: + retry_on_http_429: false + remote_timeout: 30s + staging: true + tls_config: + insecure_skip_verify: true + extra_remote_write: + - url: https://second.remote.write + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + + - it: config including remote_write.extra_write_relabel_configs and not metric relabels + set: + licenseKey: license-key-test + cluster: cluster-test + metric_type_override: + enabled: false + config: + newrelic_remote_write: + extra_write_relabel_configs: + - source_labels: + - __name__ + - instance + regex: node_memory_active_bytes;localhost:9100 + action: drop + + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + newrelic_remote_write: + extra_write_relabel_configs: + - action: drop + regex: node_memory_active_bytes;localhost:9100 + source_labels: + - __name__ + - instance + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + + - it: cluster_name is set from global + set: + licenseKey: license-key-test + global: + cluster: "test" + metric_type_override: + enabled: false + config: + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + cluster_name: test + scrape_interval: 30s + - it: cluster_name local value has precedence over global precedence + set: + licenseKey: license-key-test + global: + cluster: "test" + cluster: "test2" + metric_type_override: + enabled: false + config: + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + cluster_name: test2 + scrape_interval: 30s + - it: cluster_name is not overwritten from customAttributes + set: + licenseKey: license-key-test + global: + cluster: "test" + cluster: "test2" + customAttributes: + cluster_name: "test3" + metric_type_override: + enabled: false + config: + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + cluster_name: test2 + scrape_interval: 30s + + - it: cluster_name has precedence over extra labels has precedence over customAttributes + set: + licenseKey: license-key-test + cluster: test + customAttributes: + attribute: "value" + one: error + cluster_name: "different" + metric_type_override: + enabled: false + config: + common: + external_labels: + one: two + cluster_name: "different" + scrape_interval: 15 + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + attribute: value + cluster_name: test + one: two + scrape_interval: 15 + + - it: config including static_targets overwritten with most possible sections + set: + licenseKey: license-key-test + cluster: cluster-test + metric_type_override: + enabled: false + config: + static_targets: + jobs: + - job_name: my-custom-target-authorization-full + targets: + - "192.168.3.1:2379" + params: + q: [ "puppies" ] + oe: [ "utf8" ] + scheme: "https" + body_size_limit: 100MiB + sample_limit: 2000 + target_limit: 2000 + label_limit: 2000 + label_name_length_limit: 2000 + label_value_length_limit: 2000 + scrape_interval: 15s + scrape_timeout: 15s + tls_config: + insecure_skip_verify: true + ca_file: /path/to/ca.crt + key_file: /path/to/key.crt + cert_file: /path/to/cert.crt + server_name: server.name + min_version: TLS12 + authorization: + type: Bearer + credentials: "fancy-credentials" + extra_relabel_config: + - source_labels: [ '__name__', 'instance' ] + regex: node_memory_active_bytes;localhost:9100 + action: drop + extra_metric_relabel_config: + - source_labels: [ '__name__', 'instance' ] + regex: node_memory_active_bytes;localhost:9100 + action: drop + extra_scrape_configs: + - job_name: extra-scrape-config + static_configs: + - targets: + - "192.168.3.1:2379" + labels: + label1: value1 + label2: value2 + scrape_interval: 15s + scrape_timeout: 15s + tls_config: + insecure_skip_verify: true + ca_file: /path/to/ca.crt + key_file: /path/to/key.crt + cert_file: /path/to/cert.crt + server_name: server.name + min_version: TLS12 + authorization: + type: Bearer + credentials: "fancy-credentials" + relabel_configs: + - source_labels: [ '__name__', 'instance' ] + regex: node_memory_active_bytes;localhost:9100 + action: drop + metric_relabel_configs: + - source_labels: [ '__name__', 'instance' ] + regex: node_memory_active_bytes;localhost:9100 + action: drop + # Set empty to make this test simple + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + static_targets: + jobs: + - authorization: + credentials: fancy-credentials + type: Bearer + body_size_limit: 100MiB + extra_metric_relabel_config: + - action: drop + regex: node_memory_active_bytes;localhost:9100 + source_labels: + - __name__ + - instance + extra_relabel_config: + - action: drop + regex: node_memory_active_bytes;localhost:9100 + source_labels: + - __name__ + - instance + job_name: my-custom-target-authorization-full + label_limit: 2000 + label_name_length_limit: 2000 + label_value_length_limit: 2000 + params: + oe: + - utf8 + q: + - puppies + sample_limit: 2000 + scheme: https + scrape_interval: 15s + scrape_timeout: 15s + target_limit: 2000 + targets: + - 192.168.3.1:2379 + tls_config: + ca_file: /path/to/ca.crt + cert_file: /path/to/cert.crt + insecure_skip_verify: true + key_file: /path/to/key.crt + min_version: TLS12 + server_name: server.name + extra_scrape_configs: + - authorization: + credentials: fancy-credentials + type: Bearer + job_name: extra-scrape-config + metric_relabel_configs: + - action: drop + regex: node_memory_active_bytes;localhost:9100 + source_labels: + - __name__ + - instance + relabel_configs: + - action: drop + regex: node_memory_active_bytes;localhost:9100 + source_labels: + - __name__ + - instance + scrape_interval: 15s + scrape_timeout: 15s + static_configs: + - labels: + label1: value1 + label2: value2 + targets: + - 192.168.3.1:2379 + tls_config: + ca_file: /path/to/ca.crt + cert_file: /path/to/cert.crt + insecure_skip_verify: true + key_file: /path/to/key.crt + min_version: TLS12 + server_name: server.name + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + + - it: kubernetes config section custom values + set: + licenseKey: license-key-test + cluster: cluster-test + metric_type_override: + enabled: false + config: + kubernetes: + integrations_filter: + enabled: false + jobs: + - job_name_prefix: pod-job + target_discovery: + pod: true + endpoints: false + filter: + annotations: + custom/scrape-pod: true + - job_name_prefix: endpoints-job + target_discovery: + pod: false + endpoints: true + filter: + annotations: + custom/scrape-endpoints: true + # Set empty to make this test simple + static_targets: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + kubernetes: + jobs: + - job_name_prefix: pod-job + target_discovery: + endpoints: false + filter: + annotations: + custom/scrape-pod: true + pod: true + - job_name_prefix: endpoints-job + target_discovery: + endpoints: true + filter: + annotations: + custom/scrape-endpoints: true + pod: false + integrations_filter: + app_values: + - redis + - traefik + - calico + - nginx + - coredns + - kube-dns + - etcd + - cockroachdb + - velero + - harbor + - argocd + enabled: false + source_labels: + - app.kubernetes.io/name + - app.newrelic.io/name + - k8s-app + + - it: sharding empty not propagated + set: + licenseKey: license-key-test + cluster: cluster-test + sharding: + metric_type_override: + enabled: false + config: + kubernetes: + static_targets: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + + - it: sharding config custom values + set: + licenseKey: license-key-test + cluster: cluster-test + sharding: + total_shards_count: 2 + metric_type_override: + enabled: false + config: + kubernetes: + static_targets: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + sharding: + total_shards_count: 2 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/configurator_image_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/configurator_image_test.yaml new file mode 100644 index 000000000..0f5da69bf --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/configurator_image_test.yaml @@ -0,0 +1,57 @@ +suite: test image +templates: + - templates/statefulset.yaml + - templates/configmap.yaml +tests: + - it: configurator image is set + set: + licenseKey: license-key-test + cluster: cluster-test + images: + configurator: + tag: "test" + pullPolicy: Never + prometheus: + tag: "test-2" + asserts: + - template: templates/statefulset.yaml + equal: + path: spec.template.spec.initContainers[0].image + value: "newrelic/newrelic-prometheus-configurator:test" + - equal: + path: spec.template.spec.initContainers[0].imagePullPolicy + value: "Never" + template: templates/statefulset.yaml + - template: templates/statefulset.yaml + equal: + path: spec.template.spec.containers[0].image + value: "quay.io/prometheus/prometheus:test-2" + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: "IfNotPresent" + template: templates/statefulset.yaml + + - it: has a linux node selector by default + set: + licenseKey: license-key-test + cluster: my-cluster + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + template: templates/statefulset.yaml + + - it: has a linux node selector and additional selectors + set: + licenseKey: license-key-test + cluster: my-cluster + nodeSelector: + aCoolTestLabel: aCoolTestValue + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + aCoolTestLabel: aCoolTestValue + template: templates/statefulset.yaml diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/integration_filters_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/integration_filters_test.yaml new file mode 100644 index 000000000..d1813f135 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/integration_filters_test.yaml @@ -0,0 +1,119 @@ +suite: test configmap with IntegrationFilter +templates: + - templates/configmap.yaml +tests: + - it: config with IntegrationFilter true + set: + licenseKey: license-key-test + cluster: cluster-test + metric_type_override: + enabled: false + config: + kubernetes: + integrations_filter: + enabled: true + # Set empty to make this test simple + static_targets: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + kubernetes: + jobs: + - job_name_prefix: default + target_discovery: + endpoints: true + filter: + annotations: + prometheus.io/scrape: true + pod: true + - integrations_filter: + enabled: false + job_name_prefix: newrelic + target_discovery: + endpoints: true + filter: + annotations: + newrelic.io/scrape: true + pod: true + integrations_filter: + app_values: + - redis + - traefik + - calico + - nginx + - coredns + - kube-dns + - etcd + - cockroachdb + - velero + - harbor + - argocd + enabled: true + source_labels: + - app.kubernetes.io/name + - app.newrelic.io/name + - k8s-app + + - it: config with IntegrationFilter false + set: + licenseKey: license-key-test + cluster: cluster-test + metric_type_override: + enabled: false + config: + kubernetes: + integrations_filter: + enabled: false + # Set empty to make this test simple + static_targets: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + kubernetes: + jobs: + - job_name_prefix: default + target_discovery: + endpoints: true + filter: + annotations: + prometheus.io/scrape: true + pod: true + - integrations_filter: + enabled: false + job_name_prefix: newrelic + target_discovery: + endpoints: true + filter: + annotations: + newrelic.io/scrape: true + pod: true + integrations_filter: + app_values: + - redis + - traefik + - calico + - nginx + - coredns + - kube-dns + - etcd + - cockroachdb + - velero + - harbor + - argocd + enabled: false + source_labels: + - app.kubernetes.io/name + - app.newrelic.io/name + - k8s-app diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/lowdatamode_configmap_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/lowdatamode_configmap_test.yaml new file mode 100644 index 000000000..ac3953df6 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/tests/lowdatamode_configmap_test.yaml @@ -0,0 +1,138 @@ +suite: test configmap with LowDataMode +templates: + - templates/configmap.yaml +tests: + - it: config with lowDataMode true + set: + licenseKey: license-key-test + cluster: cluster-test + lowDataMode: true + metric_type_override: + enabled: false + config: + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + newrelic_remote_write: + extra_write_relabel_configs: + - action: drop + regex: kube_.+|container_.+|machine_.+|cadvisor_.+ + source_labels: + - __name__ + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + + - it: config with lowDataMode and nrStaging true + set: + licenseKey: license-key-test + cluster: cluster-test + lowDataMode: true + nrStaging: true + metric_type_override: + enabled: false + config: + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + newrelic_remote_write: + extra_write_relabel_configs: + - action: drop + regex: kube_.+|container_.+|machine_.+|cadvisor_.+ + source_labels: + - __name__ + staging: true + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + + - it: config with lowDataMode true from global config + set: + global: + lowDataMode: true + licenseKey: license-key-test + cluster: cluster-test + metric_type_override: + enabled: false + config: + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + newrelic_remote_write: + extra_write_relabel_configs: + - action: drop + regex: kube_.+|container_.+|machine_.+|cadvisor_.+ + source_labels: + - __name__ + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s + + - it: existing relabel configs are appended to low data mode and metric_type_override relabel configs. + set: + lowDataMode: true + licenseKey: license-key-test + cluster: cluster-test + metric_type_override: + enabled: true + config: + newrelic_remote_write: + extra_write_relabel_configs: + - action: drop + regex: my_custom_metric_relabel_config + source_labels: + - __name__ + # Set empty to make this test simple + static_targets: + kubernetes: + asserts: + - equal: + path: data["config.yaml"] + value: |- + # Configuration for newrelic-prometheus-configurator + newrelic_remote_write: + extra_write_relabel_configs: + - action: drop + regex: kube_.+|container_.+|machine_.+|cadvisor_.+ + source_labels: + - __name__ + - action: replace + regex: timeseries_write_(.*) + replacement: counter + separator: ; + source_labels: + - __name__ + target_label: newrelic_metric_type + - action: replace + regex: sql_byte(.*) + replacement: counter + separator: ; + source_labels: + - __name__ + target_label: newrelic_metric_type + - action: drop + regex: my_custom_metric_relabel_config + source_labels: + - __name__ + common: + external_labels: + cluster_name: cluster-test + scrape_interval: 30s diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/values.yaml new file mode 100644 index 000000000..2fb3ed7bc --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/newrelic-prometheus-agent/values.yaml @@ -0,0 +1,473 @@ +# -- Override the name of the chart +nameOverride: "" +# -- Override the full name of the release +fullnameOverride: "" + +# -- Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster`. +# Note it will be set as an external label in prometheus configuration, it will have precedence over `config.common.external_labels.cluster_name` +# and `customAttributes.cluster_name``. +cluster: "" +# -- This set this license key to use. Can be configured also with `global.licenseKey` +licenseKey: "" +# -- In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` +customSecretName: "" +# -- In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` +customSecretLicenseKey: "" + +# -- Adds extra attributes to prometheus external labels. Can be configured also with `global.customAttributes`. Please note, values defined +# in `common.config.externar_labels` will have precedence over `customAttributes`. +customAttributes: {} + +# Images used by the chart for prometheus and New Relic configurator. +# @default See `values.yaml` +images: + # -- The secrets that are needed to pull images from a custom registry. + pullSecrets: [] + + # -- Image for New Relic configurator. + # @default -- See `values.yaml` + configurator: + registry: "" + repository: newrelic/newrelic-prometheus-configurator + pullPolicy: IfNotPresent + # @default It defaults to `annotation.configuratorVersion` in `Chart.yaml`. + tag: "" + # -- Image for prometheus which is executed in agent mode. + # @default -- See `values.yaml` + prometheus: + registry: "" + repository: quay.io/prometheus/prometheus + pullPolicy: IfNotPresent + # @default It defaults to `appVersion` in `Chart.yaml`. + tag: "" + +# -- Volumes to mount in the containers +extraVolumes: [] +# -- Defines where to mount volumes specified with `extraVolumes` +extraVolumeMounts: [] + +# -- Settings controlling ServiceAccount creation. +# @default -- See `values.yaml` +serviceAccount: + # -- Whether the chart should automatically create the ServiceAccount objects required to run. + create: true + annotations: {} + # If not set and create is true, a name is generated using the full name template + name: "" + +# -- Additional labels for chart objects. Can be configured also with `global.labels` +labels: {} +# -- Annotations to be added to all pods created by the integration. +podAnnotations: {} +# -- Additional labels for chart pods. Can be configured also with `global.podLabels` +podLabels: {} + +# -- Resource limits to be added to all pods created by the integration. +# @default -- `{}` +resources: + prometheus: {} + +# -- Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` +priorityClassName: "" +# -- (bool) Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` +# @default -- `false` +hostNetwork: +# -- Sets security context (at pod level). Can be configured also with `global.podSecurityContext` +podSecurityContext: {} +# -- Sets security context (at container level). Can be configured also with `global.containerSecurityContext` +containerSecurityContext: {} + +# -- Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` +dnsConfig: {} + +# Settings controlling RBAC objects creation. +rbac: + # -- Whether the chart should automatically create the RBAC objects required to run. + create: true + # -- Whether the chart should create Pod Security Policy objects. + pspEnabled: false + +# -- Sets pod/node affinities set almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) +affinity: {} +# -- Sets pod's node selector almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) +nodeSelector: {} +# -- Sets pod's tolerations to node taints almost globally. (See [Affinities and tolerations](README.md#affinities-and-tolerations)) +tolerations: [] + +# -- (bool) Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` +# @default -- `false` +nrStaging: + +# -- (bool) Reduces the number of metrics sent in order to reduce costs. It can be configured also with `global.lowDataMode`. +# Specifically, it makes Prometheus stop reporting some Kubernetes cluster-specific metrics, you can see details in `static/lowdatamodedefaults.yaml`. +# @default -- false +lowDataMode: + +# -- It holds the configuration for metric type override. If enabled, a series of metric relabel configs will be added to +# `config.newrelic_remote_write.extra_write_relabel_configs`, you can check the whole list in `static/metrictyperelabeldefaults.yaml` +metric_type_override: + enabled: true + +# -- Set up Prometheus replicas to allow horizontal scalability. +# @default -- See `values.yaml` +sharding: + # -- Sets the number of Prometheus instances running on sharding mode. + # @default -- `1` + # total_shards_count: + +# -- (bool) Sets the debug log to Prometheus and prometheus-configurator or all integrations if it is set globally. Can be configured also with `global.verboseLog` +# @default -- `false` +verboseLog: + +# -- It holds the New Relic Prometheus configuration. Here you can easily set up Prometheus to get set metrics, discover +# ponds and endpoints Kubernetes and send metrics to New Relic using remote-write. +# @default -- See `values.yaml` +config: + # -- Include global configuration for Prometheus agent. + # @default -- See `values.yaml` + common: + # -- The labels to add to any timeseries that this Prometheus instance scrapes. + # @default -- `{}` + # external_labels: + # label_key_example: foo-bar + # -- How frequently to scrape targets by default, unless a different value is specified on the job. + scrape_interval: 30s + # -- The default timeout when scraping targets. + # @default -- `10s` + # scrape_timeout: + + # -- (object) Newrelic remote-write configuration settings. + # @default -- See `values.yaml` + newrelic_remote_write: + # # -- Includes additional [relabel configs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config) + # # for the New Relic remote write. + # # @default -- `[]` + # extra_write_relabel_configs: [] + + # # Enable the extra_write_relabel_configs below for backwards compatibility with legacy POMI labels. + # # This helpful when migrating from POMI to ensure that Prometheus metrics will contain both labels (e.g. cluster_name and clusterName). + # # For more migration info, please visit the [migration guide](https://docs.newrelic.com/docs/infrastructure/prometheus-integrations/install-configure-prometheus-agent/migration-guide/). + # - source_labels: [namespace] + # action: replace + # target_label: namespaceName + # - source_labels: [node] + # action: replace + # target_label: nodeName + # - source_labels: [pod] + # action: replace + # target_label: podName + # - source_labels: [service] + # action: replace + # target_label: serviceName + # - source_labels: [cluster_name] + # action: replace + # target_label: clusterName + # - source_labels: [job] + # action: replace + # target_label: scrapedTargetKind + # - source_labels: [instance] + # action: replace + # target_label: scrapedTargetInstance + + # -- Set up the proxy used to send metrics to New Relic. + # @default -- `""` + # proxy_url: + + # -- # Timeout for requests to the remote write endpoint. + # @default -- `30s` + # remote_timeout: + + # -- Fine-tune remote-write behavior: . + # queue_config: + # -- Remote Write shard capacity. + # @default -- `2500` + # capacity: + # -- Maximum number of shards. + # @default -- `200` + # max_shards: + # -- Minimum number of shards. + # @default -- `1` + # min_shards: + # -- Maximum number of samples per send. + # @default -- `500` + # max_samples_per_send: + # -- Maximum time a sample will wait in the buffer. + # @default -- `5s` + # batch_send_deadline: + # -- Initial retry delay. Gets doubled for every retry. + # @default -- `30ms` + # min_backoff: + # -- Maximum retry delay. + # @default -- `5s` + # max_backoff: + # -- Retry upon receiving a 429 status code from the remote-write storage. + # @default -- `false` + # retry_on_http_429: + + # -- (object) It includes additional remote-write configuration. Note this configuration is not parsed, so valid + # [prometheus remote_write configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write) + # should be provided. + extra_remote_write: + + # -- It allows defining scrape jobs for Kubernetes in a simple way. + # @default -- See `values.yaml` + kubernetes: + # NewRelic provides a list of Dashboards, alerts and entities for several Services. The integrations_filter configuration + # allows to scrape only the targets having this experience out of the box. + # If integrations_filter is enabled, then the jobs scrape merely the targets having one of the specified labels matching + # one of the values of app_values. + # Under the hood, a relabel_configs with 'action=keep' are generated, consider it in case any custom extra_relabel_config is needed. + integrations_filter: + # -- enabling the integration filters, merely the targets having one of the specified labels matching + # one of the values of app_values are scraped. Each job configuration can override this default. + enabled: true + # -- source_labels used to fetch label values in the relabel config added by the integration filters configuration + source_labels: ["app.kubernetes.io/name", "app.newrelic.io/name", "k8s-app"] + # -- app_values used to create the regex used in the relabel config added by the integration filters configuration. + # Note that a single regex will be created from this list, example: '.*(?i)(app1|app2|app3).*' + app_values: ["redis", "traefik", "calico", "nginx", "coredns", "kube-dns", "etcd", "cockroachdb", "velero", "harbor", "argocd"] + + # Kubernetes jobs define [kubernetes_sd_configs](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config) + # to discover and scrape Kubernetes objects. Besides, a set of relabel_configs are included in order to include some Kubernetes metadata as + # Labels. For example, address, metrics_path, URL scheme, prometheus_io_parameters, namespace, pod name, service name and labels are taken + # to set the corresponding labels. + # Please note, the relabeling allows configuring the pod/endpoints scrape using the following annotations: + # - `prometheus.io/scheme`: If the metrics endpoint is secured then you will need to set this to `https` + # - `prometheus.io/path`: If the metrics path is not `/metrics` override this. + # - `prometheus.io/port`: If the metrics are exposed on a different port to the service for service endpoints or to + # the default 9102 for pods. + # - `prometheus.io/param_`: To include additional parameters in the scrape URL. + jobs: + # 'default' scrapes all targets having 'prometheus.io/scrape: true'. + # Out of the box, since kubernetes.integrations_filter.enabled=true then only targets selected by the integration filters are considered. + - job_name_prefix: default + target_discovery: + pod: true + endpoints: true + filter: + annotations: + prometheus.io/scrape: true + # -- integrations_filter configuration for this specific job. It overrides kubernetes.integrations_filter configuration + # integrations_filter: + + # 'newrelic' scrapes all targets having 'newrelic.io/scrape: true'. + # This is useful to extend the targets scraped by the 'default' job allowlisting services leveraging `newrelic.io/scrape` annotation + - job_name_prefix: newrelic + integrations_filter: + enabled: false + target_discovery: + pod: true + endpoints: true + filter: + annotations: + newrelic.io/scrape: true + + # -- Set up the job name prefix. The final Prometheus `job` name will be composed of + the target discovery kind. ie: `default-pod` + # @default -- `""` + # - job_name_prefix: + + # -- The target discovery field allows customizing how Kubernetes discovery works. + # target_discovery: + + # -- Whether pods should be discovered. + # @default -- `false` + # pod: + + # -- Whether endpoints should be discovered. + # @default -- `false` + # endpoints: + + # -- Defines filtering criteria, it is possible to set labels and/or annotations. All filters will apply (defined + # filters are taken into account as an "AND operation"). + # @default -- `{}` + # filter: + # -- Map of annotations that the targets should have. If only the annotation name is defined, the filter only checks if exists. + # @default -- `{}` + # annotations: + + # -- Map of labels that the targets should have. If only the label name is defined, the filter only checks if exists. + # @default -- `{}` + # labels: + + # -- Advanced configs of the Kubernetes service discovery `kuberentes_sd_config` options, + # check [prometheus documentation](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config) for details. + # Notice that using `filter` is the recommended way to filter targets to avoid adding load to the API Server. + # additional_config: + # kubeconfig_file: "" + # namespaces: {} + # selectors: {} + # attach_metadata: {} + + + # -- The HTTP resource path on which to fetch metrics from targets. + # Use `prometheus.io/path` pod/service annotation to override this or modify it here. + # @default -- `/metrics` + # metrics_path: + + # -- Optional HTTP URL parameters. + # Use `prometheus.io/param_` pod/service annotation to include additional parameters in the scrape url or modify it here. + # @default -- `{}` + # params: + + # -- Configures the protocol scheme used for requests. + # Annotate the service/pod with `prometheus.io/scheme=https` if the secured port is used or modify it here. + # @default -- `http` + # scheme: + + # -- How frequently to scrape targets from this job. + # @default -- defined in `common.scrape_interval` + # scrape_interval: + + # -- Per-scrape timeout when scraping this job. + # @default -- defined in `common.scrape_timeout` + # scrape_timeout: + + # -- Configures the scrape request's TLS settings. + # @default -- `{}` + # tls_config: + # -- CA certificate file path to validate API server certificate with. + # @default -- `""` + # ca_file: + + # -- Certificate and key files path for client cert authentication to the server. + # @default -- `""` + # cert_file: + # key_file: + + # Disable validation of the server certificate. + # @default -- `false` + # insecure_skip_verify: + + # -- Sets the `Authorization` Bearer token header on every scrape request + # @default -- `{}` + # authorization: + # Sets the credentials to the credentials read from the configured file. + # @default -- `""` + # credentials_file: + + # -- Sets the `Authorization` header on every scrape request with the configured username and password. + # @default -- `{}` + # basic_auth: + # username: + # password_file: + + # -- List of relabeling configurations. Used if needed to add any special filter or label manipulation before the scrape takes place. + # @default -- `[]` + # extra_relabel_config: + + # -- List of metric relabel configurations. Used it to filter metrics and labels after scrape. + # @default -- `[]` + # extra_metric_relabel_config: + + + # -- It allows defining scrape jobs for targets with static URLs. + # @default -- See `values.yaml`. + static_targets: + # -- List of static target jobs. By default, it defines a job to get self-metrics. Please note, if you define `static_target.jobs` and would like to keep + # self-metrics you need to include a job like the one defined by default. + # @default -- See `values.yaml`. + jobs: + - job_name: self-metrics + skip_sharding: true # sharding is skipped to obtain self-metrics from all Prometheus servers. + targets: + - "localhost:9090" + extra_metric_relabel_config: + - source_labels: [__name__] + regex: "\ + prometheus_agent_active_series|\ + prometheus_target_interval_length_seconds|\ + prometheus_target_scrape_pool_targets|\ + prometheus_remote_storage_samples_pending|\ + prometheus_remote_storage_samples_in_total|\ + prometheus_remote_storage_samples_retried_total|\ + prometheus_agent_corruptions_total|\ + prometheus_remote_storage_shards|\ + prometheus_sd_kubernetes_events_total|\ + prometheus_agent_checkpoint_creations_failed_total|\ + prometheus_agent_checkpoint_deletions_failed_total|\ + prometheus_remote_storage_samples_dropped_total|\ + prometheus_remote_storage_samples_failed_total|\ + prometheus_sd_kubernetes_http_request_total|\ + prometheus_agent_truncate_duration_seconds_sum|\ + prometheus_build_info|\ + process_resident_memory_bytes|\ + process_virtual_memory_bytes|\ + process_cpu_seconds_total|\ + prometheus_remote_storage_bytes_total" + action: keep + + # -- The job name assigned to scraped metrics by default. + # @default -- `""`. + # - job_name: + # -- List of target URLs to be scraped by this job. + # @default -- `[]`. + # targets: + + # -- Labels assigned to all metrics scraped from the targets. + # @default -- `{}`. + # labels: + + # -- The HTTP resource path on which to fetch metrics from targets. + # @default -- `/metrics` + # metrics_path: + + # -- Optional HTTP URL parameters. + # @default -- `{}` + # params: + + # -- Configures the protocol scheme used for requests. + # @default -- `http` + # scheme: + + # -- How frequently to scrape targets from this job. + # @default -- defined in `common.scrape_interval` + # scrape_interval: + + # -- Per-scrape timeout when scraping this job. + # @default -- defined in `common.scrape_timeout` + # scrape_timeout: + + # -- Configures the scrape request's TLS settings. + # @default -- `{}` + # tls_config: + # -- CA certificate file path to validate API server certificate with. + # @default -- `""` + # ca_file: + + # -- Certificate and key files path for client cert authentication to the server. + # @default -- `""` + # cert_file: + # key_file: + + # Disable validation of the server certificate. + # @default -- `false` + # insecure_skip_verify: + + # -- Sets the `Authorization` Bearer token header on every scrape request + # @default -- `{}` + # authorization: + # Sets the credentials to the credentials read from the configured file. + # @default -- `""` + # credentials_file: + + # -- Sets the `Authorization` header on every scrape request with the configured username and password. + # @default -- `{}` + # basic_auth: + # username: + # password_file: + + # -- List of relabeling configurations. Used if needed to add any special filter or label manipulation before the scrape takes place. + # @default -- `[]` + # extra_relabel_config: + + # -- List of metric relabel configurations. Used it to filter metrics and labels after scrape. + # @default -- `[]` + # extra_metric_relabel_config: + + + # -- It is possible to include extra scrape configuration in [prometheus format](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config). + # Please note, it should be a valid Prometheus configuration which will not be parsed by the chart. + # WARNING extra_scrape_configs is a raw Prometheus config. Therefore, the metrics collected thanks to it will not have by default the metadata (pod_name, service_name, ...) added by the configurator for the static or kubernetes jobs. + # This configuration should be used as a workaround whenever kubernetes and static job do not cover a particular use-case. + # @default -- `[]` + extra_scrape_configs: [] diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/Chart.lock new file mode 100644 index 000000000..dff6eab20 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +digest: sha256:fa87cb007564a39a72739a3e850a91d6b03c0fc27a1115deac042b3ef77b4142 +generated: "2024-06-21T19:47:28.685291839Z" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/Chart.yaml new file mode 100644 index 000000000..c0be1a606 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +appVersion: 2.10.1 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +description: A Helm chart to deploy the New Relic Kube Events router +home: https://docs.newrelic.com/docs/integrations/kubernetes-integration/kubernetes-events/install-kubernetes-events-integration +icon: https://newrelic.com/themes/custom/curio/assets/mediakit/NR_logo_Horizontal.svg +keywords: +- infrastructure +- newrelic +- monitoring +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +name: nri-kube-events +sources: +- https://github.com/newrelic/nri-kube-events/ +- https://github.com/newrelic/nri-kube-events/tree/main/charts/nri-kube-events +- https://github.com/newrelic/infrastructure-agent/ +version: 3.10.1 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/README.md new file mode 100644 index 000000000..6a5365e67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/README.md @@ -0,0 +1,79 @@ +# nri-kube-events + +![Version: 3.10.1](https://img.shields.io/badge/Version-3.10.1-informational?style=flat-square) ![AppVersion: 2.10.1](https://img.shields.io/badge/AppVersion-2.10.1-informational?style=flat-square) + +A Helm chart to deploy the New Relic Kube Events router + +**Homepage:** + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add nri-kube-events https://newrelic.github.io/nri-kube-events +helm upgrade --install nri-kube-events/nri-kube-events -f your-custom-values.yaml +``` + +## Source Code + +* +* +* + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Sets pod/node affinities. Can be configured also with `global.affinity` | +| agentHTTPTimeout | string | `"30s"` | Amount of time to wait until timeout to send metrics to the metric forwarder | +| cluster | string | `""` | Name of the Kubernetes cluster monitored. Mandatory. Can be configured also with `global.cluster` | +| containerSecurityContext | object | `{}` | Sets security context (at container level). Can be configured also with `global.containerSecurityContext` | +| customAttributes | object | `{}` | Adds extra attributes to the cluster and all the metrics emitted to the backend. Can be configured also with `global.customAttributes` | +| customSecretLicenseKey | string | `""` | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` | +| customSecretName | string | `""` | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` | +| deployment.annotations | object | `{}` | Annotations to add to the Deployment. | +| dnsConfig | object | `{}` | Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` | +| fedramp.enabled | bool | `false` | Enables FedRAMP. Can be configured also with `global.fedramp.enabled` | +| forwarder | object | `{"resources":{}}` | Resources for the forwarder sidecar container | +| fullnameOverride | string | `""` | Override the full name of the release | +| hostNetwork | bool | `false` | Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` | +| images | object | See `values.yaml` | Images used by the chart for the integration and agents | +| images.agent | object | See `values.yaml` | Image for the New Relic Infrastructure Agent sidecar | +| images.integration | object | See `values.yaml` | Image for the New Relic Kubernetes integration | +| images.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | +| labels | object | `{}` | Additional labels for chart objects | +| licenseKey | string | `""` | This set this license key to use. Can be configured also with `global.licenseKey` | +| nameOverride | string | `""` | Override the name of the chart | +| nodeSelector | object | `{}` | Sets pod's node selector. Can be configured also with `global.nodeSelector` | +| nrStaging | bool | `false` | Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` | +| podAnnotations | object | `{}` | Annotations to add to the pod. | +| podLabels | object | `{}` | Additional labels for chart pods | +| podSecurityContext | object | `{}` | Sets security context (at pod level). Can be configured also with `global.podSecurityContext` | +| priorityClassName | string | `""` | Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` | +| proxy | string | `""` | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port`. Can be configured also with `global.proxy` | +| rbac.create | bool | `true` | Specifies whether RBAC resources should be created | +| resources | object | `{}` | Resources for the integration container | +| scrapers | object | See `values.yaml` | Configure the various kinds of scrapers that should be run. | +| serviceAccount | object | See `values.yaml` | Settings controlling ServiceAccount creation | +| serviceAccount.create | bool | `true` | Specifies whether a ServiceAccount should be created | +| sinks | object | See `values.yaml` | Configure where will the metrics be written. Mostly for debugging purposes. | +| sinks.newRelicInfra | bool | `true` | The newRelicInfra sink sends all events to New Relic. | +| sinks.stdout | bool | `false` | Enable the stdout sink to also see all events in the logs. | +| tolerations | list | `[]` | Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` | +| verboseLog | bool | `false` | Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` | + +## Maintainers + +* [juanjjaramillo](https://github.com/juanjjaramillo) +* [csongnr](https://github.com/csongnr) +* [dbudziwojskiNR](https://github.com/dbudziwojskiNR) diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/README.md.gotmpl new file mode 100644 index 000000000..e77eb7f14 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/README.md.gotmpl @@ -0,0 +1,43 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add nri-kube-events https://newrelic.github.io/nri-kube-events +helm upgrade --install nri-kube-events/nri-kube-events -f your-custom-values.yaml +``` + +{{ template "chart.sourcesSection" . }} + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +{{ template "chart.valuesSection" . }} + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/Chart.yaml new file mode 100644 index 000000000..b65ac15d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +- name: kang-makes + url: https://github.com/kang-makes +name: common-library +type: library +version: 1.2.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/DEVELOPERS.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/DEVELOPERS.md new file mode 100644 index 000000000..3ccc108e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/DEVELOPERS.md @@ -0,0 +1,663 @@ +# Functions/templates documented for chart writers +Here is some rough documentation separated by the file that contains the function, the function +name and how to use it. We are not covering functions that start with `_` (e.g. +`newrelic.common.license._licenseKey`) because they are used internally by this library for +other helpers. Helm does not have the concept of "public" or "private" functions/templates so +this is a convention of ours. + +## _naming.tpl +These functions are used to name objects. + +### `newrelic.common.naming.name` +This is the same as the idiomatic `CHART-NAME.name` that is created when you use `helm create`. + +It honors `.Values.nameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.name" . }} +``` + +### `newrelic.common.naming.fullname` +This is the same as the idiomatic `CHART-NAME.fullname` that is created when you use `helm create` + +It honors `.Values.fullnameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.fullname" . }} +``` + +### `newrelic.common.naming.chart` +This is the same as the idiomatic `CHART-NAME.chart` that is created when you use `helm create`. + +It is mostly useless for chart writers. It is used internally for templating the labels but there +is no reason to keep it "private". + +Usage: +```mustache +{{ include "newrelic.common.naming.chart" . }} +``` + +### `newrelic.common.naming.truncateToDNS` +This is a useful template that could be used to trim a string to 63 chars and does not end with a dash (`-`). +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $truncatedName := include "newrelic.common.naming.truncateToDNS" $nameToTruncate }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-string-that-should-be */ -}} +``` + +### `newrelic.common.naming.truncateToDNSWithSuffix` +This template function is the same as the above but instead of receiving a string you should give a `dict` +with a `name` and a `suffix`. This function will join them with a dash (`-`) and trim the `name` so the +result of `name-suffix` is no more than 63 chars + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $suffix := "A-NOT-SO-LONG-SUFFIX" }} +{{- $truncatedName := include "truncateToDNSWithSuffix" (dict "name" $nameToTruncate "suffix" $suffix) }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-A-NOT-SO-LONG-SUFFIX */ -}} +``` + + + +## _labels.tpl +### `newrelic.common.labels`, `newrelic.common.labels.selectorLabels` and `newrelic.common.labels.podLabels` +These are functions that are used to label objects. They are configured by this `values.yaml` +```yaml +global: + podLabels: {} # included in all the pods of all the charts that implement this library + labels: {} # included in all the objects of all the charts that implement this library +podLabels: {} # included in all the pods of this chart +labels: {} # included in all the objects of this chart +``` + +label maps are merged from global to local values. + +And chart writer should use them like this: +```mustache +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} +``` + +`newrelic.common.labels.podLabels` includes `newrelic.common.labels.selectorLabels` automatically. + + + +## _priority-class-name.tpl +### `newrelic.common.priorityClassName` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + priorityClassName: "" +priorityClassName: "" +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `priorityClassName` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} +``` + + + +## _hostnetwork.tpl +### `newrelic.common.hostNetwork` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + hostNetwork: # Note that this is empty (nil) +hostNetwork: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `hostNetwork` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.hostNetwork" . }} + hostNetwork: {{ . }} + {{- end }} +``` + +### `newrelic.common.hostNetwork.value` +This function is an abstraction of the function above but this returns directly "true" or "false". + +Be careful with using this with an `if` as Helm does evaluate "false" (string) as `true`. + +Usage (example in a pod spec): +```mustache +spec: + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} +``` + + + +## _dnsconfig.tpl +### `newrelic.common.dnsConfig` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + dnsConfig: {} +dnsConfig: {} +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `dnsConfig` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _images.tpl +These functions help us to deal with how images are templated. This allows setting `registries` +where to fetch images globally while being flexible enough to fit in different maps of images +and deployments with one or more images. This is the example of a complex `values.yaml` that +we are going to use during the documentation of these functions: + +```yaml +global: + images: + registry: nexus-3-instance.internal.clients-domain.tld +jobImage: + registry: # defaults to "example.tld" when empty in these examples + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent + pullSecrets: [] +images: + integration: + registry: + repository: newrelic/nri-kube-events + tag: 1.8.0 + pullPolicy: IfNotPresent + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.22.0 + pullPolicy: IfNotPresent + pullSecrets: [] +``` + +### `newrelic.common.images.image` +This will return a string with the image ready to be downloaded that includes the registry, the image and the tag. +`defaultRegistry` is used to keep `registry` field empty in `values.yaml` so you can override the image using +`global.images.registry`, your local `jobImage.registry` and be able to fallback to a registry that is not `docker.io` +(Or the default repository that the client could have set in the CRI). + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.image" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.registry` +It returns the registry from the global or local values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.registry" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.repository` +It returns the image from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.tag` +It returns the image's tag from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.renderPullSecrets` +If returns a merged map that contains the pull secrets from the global configuration and the local one. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.jobImage.pullSecrets "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +``` + + + +## _serviceaccount.tpl +These functions are used to evaluate if the service account should be created, with which name and add annotations to it. + +The functions that the common library has implemented for service accounts are: +* `newrelic.common.serviceAccount.create` +* `newrelic.common.serviceAccount.name` +* `newrelic.common.serviceAccount.annotations` + +Usage: +```mustache +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +``` + + + +## _affinity.tpl, _nodeselector.tpl and _tolerations.tpl +These three files are almost the same and they follow the idiomatic way of `helm create`. + +Each function also looks if there is a global value like the other helpers. +```yaml +global: + affinity: {} + nodeSelector: {} + tolerations: [] +affinity: {} +nodeSelector: {} +tolerations: [] +``` + +The values here are replaced instead of be merged. If a value at root level is found, the global one is ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _agent-config.tpl +### `newrelic.common.agentConfig.defaults` +This returns a YAML that the agent can use directly as a config that includes other options from the values file like verbose mode, +custom attributes, FedRAMP and such. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include newrelic.common.naming.truncateToDNSWithSuffix (dict "name" (include "newrelic.common.naming.fullname" .) suffix "agent-config") }} + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "newrelic.common.agentConfig.defaults" . | nindent 4 }} +``` + + + +## _cluster.tpl +### `newrelic.common.cluster` +Returns the cluster name + +Usage: +```mustache +{{ include "newrelic.common.cluster" . }} +``` + + + +## _custom-attributes.tpl +### `newrelic.common.customAttributes` +Return custom attributes in YAML format. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + name: example +data: + custom-attributes.yaml: | + {{- include "newrelic.common.customAttributes" . | nindent 4 }} + custom-attributes.json: | + {{- include "newrelic.common.customAttributes" . | fromYaml | toJson | nindent 4 }} +``` + + + +## _fedramp.tpl +### `newrelic.common.fedramp.enabled` +Returns true if FedRAMP is enabled or an empty string if not. It can be safely used in conditionals as an empty string is a Helm falsiness. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled" . }} +``` + +### `newrelic.common.fedramp.enabled.value` +Returns true if FedRAMP is enabled or false if not. This is to have the value of FedRAMP ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled.value" . }} +``` + + + +## _license.tpl +### `newrelic.common.license.secretName` and ### `newrelic.common.license.secretKeyName` +Returns the secret and key inside the secret where to read the license key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the license key. + +To create the secret use `newrelic.common.license.secret`. + +Usage: +```mustache +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + containers: + - name: agent + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} +``` + + + +## _license_secret.tpl +### `newrelic.common.license.secret` +This function templates the secret that is used by agents and integrations with the license Key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any license key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.license.secret" . -}} +``` + + + +## _insights.tpl +### `newrelic.common.insightsKey.secretName` and ### `newrelic.common.insightsKey.secretKeyName` +Returns the secret and key inside the secret where to read the insights key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the insights key. + +To create the secret use `newrelic.common.insightsKey.secret`. + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: statsd +spec: + containers: + - name: statsd + env: + - name: "INSIGHTS_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + key: {{ include "newrelic.common.insightsKey.secretKeyName" . }} +``` + + + +## _insights_secret.tpl +### `newrelic.common.insightsKey.secret` +This function templates the secret that is used by agents and integrations with the insights key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any insights key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.insightsKey.secret" . -}} +``` + + + +## _low-data-mode.tpl +### `newrelic.common.lowDataMode` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + lowDataMode: # Note that this is empty (nil) +lowDataMode: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `lowdataMode` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.lowDataMode" . }} +``` + + + +## _privileged.tpl +### `newrelic.common.privileged` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + privileged: # Note that this is empty (nil) +privileged: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `privileged` is defined, the global one is going to be always ignored. + +Chart writers could override this and put directly a `true` in the `values.yaml` to override the +default of the common library. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.privileged" . }} +``` + +### `newrelic.common.privileged.value` +Returns true if privileged mode is enabled or false if not. This is to have the value of privileged ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.privileged.value" . }} +``` + + + +## _proxy.tpl +### `newrelic.common.proxy` +Returns the proxy URL configured by the user. + +Usage: +```mustache +{{ include "newrelic.common.proxy" . }} +``` + + + +## _security-context.tpl +Use these functions to share the security context among all charts. Useful in clusters that have security enforcing not to +use the root user (like OpenShift) or users that have an admission webhooks. + +The functions are: +* `newrelic.common.securityContext.container` +* `newrelic.common.securityContext.pod` + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + spec: + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + containers: + - name: example + {{- with include "nriKubernetes.securityContext.container" . }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} +``` + + + +## _staging.tpl +### `newrelic.common.nrStaging` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + nrStaging: # Note that this is empty (nil) +nrStaging: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `nrStaging` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging" . }} +``` + +### `newrelic.common.nrStaging.value` +Returns true if staging is enabled or false if not. This is to have the staging value ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging.value" . }} +``` + + + +## _verbose-log.tpl +### `newrelic.common.verboseLog` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + verboseLog: # Note that this is empty (nil) +verboseLog: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `verboseLog` is defined, the global one is going to be always ignored. + +Usage: +```mustache +{{ include "newrelic.common.verboseLog" . }} +``` + +### `newrelic.common.verboseLog.valueAsBoolean` +Returns true if verbose is enabled or false if not. This is to have the verbose value ready to be templated as a boolean + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsBoolean" . }} +``` + +### `newrelic.common.verboseLog.valueAsInt` +Returns 1 if verbose is enabled or 0 if not. This is to have the verbose value ready to be templated as an integer + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsInt" . }} +``` diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/README.md new file mode 100644 index 000000000..10f08ca67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/README.md @@ -0,0 +1,106 @@ +# Helm Common library + +The common library is a way to unify the UX through all the Helm charts that implement it. + +The tooling suite that New Relic is huge and growing and this allows to set things globally +and locally for a single chart. + +## Documentation for chart writers + +If you are writing a chart that is going to use this library you can check the [developers guide](/library/common-library/DEVELOPERS.md) to see all +the functions/templates that we have implemented, what they do and how to use them. + +## Values managed globally + +We want to have a seamless experience through all the charts so we created this library that tries to standardize the behaviour +of all the charts. Sadly, because of the complexity of all these integrations, not all the charts behave exactly as expected. + +An example is `newrelic-infrastructure` that ignores `hostNetwork` in the control plane scraper because most of the users has the +control plane listening in the node to `localhost`. + +For each chart that has a special behavior (or further information of the behavior) there is a "chart particularities" section +in its README.md that explains which is the expected behavior. + +At the time of writing this, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this +library and honors global options as described in this document. + +Here is a list of global options: + +| Global keys | Local keys | Default | Merged[1](#values-managed-globally-1) | Description | +|-------------|------------|---------|--------------------------------------------------|-------------| +| global.cluster | cluster | `""` | | Name of the Kubernetes cluster monitored | +| global.licenseKey | licenseKey | `""` | | This set this license key to use | +| global.customSecretName | customSecretName | `""` | | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there | +| global.customSecretLicenseKey | customSecretLicenseKey | `""` | | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located | +| global.podLabels | podLabels | `{}` | yes | Additional labels for chart pods | +| global.labels | labels | `{}` | yes | Additional labels for chart objects | +| global.priorityClassName | priorityClassName | `""` | | Sets pod's priorityClassName | +| global.hostNetwork | hostNetwork | `false` | | Sets pod's hostNetwork | +| global.dnsConfig | dnsConfig | `{}` | | Sets pod's dnsConfig | +| global.images.registry | See [Further information](#values-managed-globally-2) | `""` | | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.images.pullSecrets | See [Further information](#values-managed-globally-2) | `[]` | yes | Set secrets to be able to fetch images | +| global.podSecurityContext | podSecurityContext | `{}` | | Sets security context (at pod level) | +| global.containerSecurityContext | containerSecurityContext | `{}` | | Sets security context (at container level) | +| global.affinity | affinity | `{}` | | Sets pod/node affinities | +| global.nodeSelector | nodeSelector | `{}` | | Sets pod's node selector | +| global.tolerations | tolerations | `[]` | | Sets pod's tolerations to node taints | +| global.serviceAccount.create | serviceAccount.create | `true` | | Configures if the service account should be created or not | +| global.serviceAccount.name | serviceAccount.name | name of the release | | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. | +| global.serviceAccount.annotations | serviceAccount.annotations | `{}` | yes | Add these annotations to the service account we create | +| global.customAttributes | customAttributes | `{}` | | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.fedramp | fedramp | `false` | | Enables FedRAMP | +| global.lowDataMode | lowDataMode | `false` | | Reduces number of metrics sent in order to reduce costs | +| global.privileged | privileged | Depends on the chart | | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | +| global.proxy | proxy | `""` | | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.nrStaging | nrStaging | `false` | | Send the metrics to the staging backend. Requires a valid staging license key | +| global.verboseLog | verboseLog | `false` | | Sets the debug/trace logs to this integration or all integrations if it is set globally | + +### Further information + +#### 1. Merged + +Merged means that the values from global are not replaced by the local ones. Think in this example: +```yaml +global: + labels: + global: global + hostNetwork: true + nodeSelector: + global: global + +labels: + local: local +nodeSelector: + local: local +hostNetwork: false +``` + +This values will template `hostNetwork` to `false`, a map of labels `{ "global": "global", "local": "local" }` and a `nodeSelector` with +`{ "local": "local" }`. + +As Helm by default merges all the maps it could be confusing that we have two behaviors (merging `labels` and replacing `nodeSelector`) +the `values` from global to local. This is the rationale behind this: +* `hostNetwork` is templated to `false` because is overriding the value defined globally. +* `labels` are merged because the user may want to label all the New Relic pods at once and label other solution pods differently for + clarity' sake. +* `nodeSelector` does not merge as `labels` because could make it harder to overwrite/delete a selector that comes from global because + of the logic that Helm follows merging maps. + + +#### 2. Fine grain registries + +Some charts only have 1 image while others that can have 2 or more images. The local path for the registry can change depending +on the chart itself. + +As this is mostly unique per helm chart, you should take a look to the chart's values table (or directly to the `values.yaml` file to see all the +images that you can change. + +This should only be needed if you have an advanced setup that forces you to have granularity enough to force a proxy/cache registry per integration. + + + +#### 3. Privileged mode + +By default, from the common library, the privileged mode is set to false. But most of the helm charts require this to be true to fetch more +metrics so could see a true in some charts. The consequences of the privileged mode differ from one chart to another so for each chart that +honors the privileged mode toggle should be a section in the README explaining which is the behavior with it enabled or disabled. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_affinity.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_affinity.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod affinity */ -}} +{{- define "newrelic.common.affinity" -}} + {{- if .Values.affinity -}} + {{- toYaml .Values.affinity -}} + {{- else if .Values.global -}} + {{- if .Values.global.affinity -}} + {{- toYaml .Values.global.affinity -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_agent-config.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..9c32861a0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,26 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +log: + level: trace +{{- end }} + +{{- if (include "newrelic.common.nrStaging" . ) }} +staging: true +{{- end }} + +{{- with include "newrelic.common.proxy" . }} +proxy: {{ . | quote }} +{{- end }} + +{{- with include "newrelic.common.fedramp.enabled" . }} +fedramp: {{ . }} +{{- end }} + +{{- with fromYaml ( include "newrelic.common.customAttributes" . ) }} +custom_attributes: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_cluster.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_cluster.tpl @@ -0,0 +1,15 @@ +{{/* +Return the cluster +*/}} +{{- define "newrelic.common.cluster" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.cluster -}} + {{- .Values.cluster -}} +{{- else if $global.cluster -}} + {{- $global.cluster -}} +{{- else -}} + {{ fail "There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required." }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_custom-attributes.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_custom-attributes.tpl @@ -0,0 +1,17 @@ +{{/* +This will render custom attributes as a YAML ready to be templated or be used with `fromYaml`. +*/}} +{{- define "newrelic.common.customAttributes" -}} +{{- $customAttributes := dict -}} + +{{- $global := index .Values "global" | default dict -}} +{{- if $global.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes $global.customAttributes -}} +{{- end -}} + +{{- if .Values.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes .Values.customAttributes -}} +{{- end -}} + +{{- toYaml $customAttributes -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_dnsconfig.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_dnsconfig.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod dnsConfig */ -}} +{{- define "newrelic.common.dnsConfig" -}} + {{- if .Values.dnsConfig -}} + {{- toYaml .Values.dnsConfig -}} + {{- else if .Values.global -}} + {{- if .Values.global.dnsConfig -}} + {{- toYaml .Values.global.dnsConfig -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_fedramp.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_fedramp.tpl @@ -0,0 +1,25 @@ +{{- /* Defines the fedRAMP flag */ -}} +{{- define "newrelic.common.fedramp.enabled" -}} + {{- if .Values.fedramp -}} + {{- if .Values.fedramp.enabled -}} + {{- .Values.fedramp.enabled -}} + {{- end -}} + {{- else if .Values.global -}} + {{- if .Values.global.fedramp -}} + {{- if .Values.global.fedramp.enabled -}} + {{- .Values.global.fedramp.enabled -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{- /* Return FedRAMP value directly ready to be templated */ -}} +{{- define "newrelic.common.fedramp.enabled.value" -}} +{{- if include "newrelic.common.fedramp.enabled" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_hostnetwork.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_hostnetwork.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the hostNetwork toggle. +This helper allows to override the global `.global.hostNetwork` with the value of `.hostNetwork`. +Returns "true" if `hostNetwork` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.hostNetwork" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- /* +`get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs + +We also want only to return when this is true, returning `false` here will template "false" (string) when doing +an `(include "newrelic.common.hostNetwork" .)`, which is not an "empty string" so it is `true` if it is used +as an evaluation somewhere else. +*/ -}} +{{- if get .Values "hostNetwork" | kindIs "bool" -}} + {{- if .Values.hostNetwork -}} + {{- .Values.hostNetwork -}} + {{- end -}} +{{- else if get $global "hostNetwork" | kindIs "bool" -}} + {{- if $global.hostNetwork -}} + {{- $global.hostNetwork -}} + {{- end -}} +{{- end -}} +{{- end -}} + + +{{- /* +Abstraction of the hostNetwork toggle. +This helper abstracts the function "newrelic.common.hostNetwork" to return true or false directly. +*/ -}} +{{- define "newrelic.common.hostNetwork.value" -}} +{{- if include "newrelic.common.hostNetwork" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_images.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..d4fb43290 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_images.tpl @@ -0,0 +1,94 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "defaultRegistry" .defaultRegistry "context" .context ) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic.common.images.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image registry +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} +{{- $globalRegistry := "" -}} +{{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- with .context.Values.global.images.registry -}} + {{- $globalRegistry = . -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- $localRegistry := "" -}} +{{- if .imageRoot.registry -}} + {{- $localRegistry = .imageRoot.registry -}} +{{- end -}} + +{{- $registry := $localRegistry | default $globalRegistry | default .defaultRegistry -}} +{{- if $registry -}} + {{- $registry -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image repository +{{ include "newrelic.common.images.repository" .Values.path.to.the.image }} +*/ -}} +{{- define "newrelic.common.images.repository" -}} + {{- .repository -}} +{{- end -}} + + + +{{- /* +Return the proper image tag +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.tag" -}} + {{- .imageRoot.tag | default .context.Chart.AppVersion | toString -}} +{{- end -}} + + + +{{- /* +Return the proper Image Pull Registry Secret Names evaluating values as templates +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.path.to.the.images.pullSecrets1, .Values.path.to.the.images.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- if .context.Values.global.images.pullSecrets -}} + {{- range .context.Values.global.images.pullSecrets -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- range .pullSecrets -}} + {{- if not (empty .) -}} + {{- range . -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if $flatlist -}} + {{- toYaml $flatlist -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_insights.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_insights.tpl new file mode 100644 index 000000000..895c37732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_insights.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the Insights Key. +*/}} +{{- define "newrelic.common.insightsKey.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "insightskey" ) -}} +{{- include "newrelic.common.insightsKey._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +*/}} +{{- define "newrelic.common.insightsKey.secretKeyName" -}} +{{- include "newrelic.common.insightsKey._customSecretKey" . | default "insightsKey" -}} +{{- end -}} + +{{/* +Return local insightsKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._licenseKey" -}} +{{- if .Values.insightsKey -}} + {{- .Values.insightsKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.insightsKey -}} + {{- .Values.global.insightsKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the Insights Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretName" -}} +{{- if .Values.customInsightsKeySecretName -}} + {{- .Values.customInsightsKeySecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretName -}} + {{- .Values.global.customInsightsKeySecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretKey" -}} +{{- if .Values.customInsightsKeySecretKey -}} + {{- .Values.customInsightsKeySecretKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretKey }} + {{- .Values.global.customInsightsKeySecretKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_insights_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_insights_secret.yaml.tpl new file mode 100644 index 000000000..556caa6ca --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_insights_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the insights key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.insightsKey.secret" }} +{{- if not (include "newrelic.common.insightsKey._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.insightsKey._licenseKey" .) }} + {{- fail "You must specify a insightsKey or a customInsightsSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.insightsKey.secretKeyName" . }}: {{ include "newrelic.common.insightsKey._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_labels.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_labels.tpl @@ -0,0 +1,54 @@ +{{/* +This will render the labels that should be used in all the manifests used by the helm chart. +*/}} +{{- define "newrelic.common.labels" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- $chart := dict "helm.sh/chart" (include "newrelic.common.naming.chart" . ) -}} +{{- $managedBy := dict "app.kubernetes.io/managed-by" .Release.Service -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $labels := mustMergeOverwrite $chart $managedBy $selectorLabels -}} +{{- if .Chart.AppVersion -}} +{{- $labels = mustMergeOverwrite $labels (dict "app.kubernetes.io/version" .Chart.AppVersion) -}} +{{- end -}} + +{{- $globalUserLabels := $global.labels | default dict -}} +{{- $localUserLabels := .Values.labels | default dict -}} + +{{- $labels = mustMergeOverwrite $labels $globalUserLabels $localUserLabels -}} + +{{- toYaml $labels -}} +{{- end -}} + + + +{{/* +This will render the labels that should be used in deployments/daemonsets template pods as a selector. +*/}} +{{- define "newrelic.common.labels.selectorLabels" -}} +{{- $name := dict "app.kubernetes.io/name" ( include "newrelic.common.naming.name" . ) -}} +{{- $instance := dict "app.kubernetes.io/instance" .Release.Name -}} + +{{- $selectorLabels := mustMergeOverwrite $name $instance -}} + +{{- toYaml $selectorLabels -}} +{{- end }} + + + +{{/* +Pod labels +*/}} +{{- define "newrelic.common.labels.podLabels" -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $global := index .Values "global" | default dict -}} +{{- $globalPodLabels := $global.podLabels | default dict }} + +{{- $localPodLabels := .Values.podLabels | default dict }} + +{{- $podLabels := mustMergeOverwrite $selectorLabels $globalPodLabels $localPodLabels -}} + +{{- toYaml $podLabels -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_license.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..647b4ff43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_license.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "license" ) -}} +{{- include "newrelic.common.license._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +*/}} +{{- define "newrelic.common.license.secretKeyName" -}} +{{- include "newrelic.common.license._customSecretKey" . | default "licenseKey" -}} +{{- end -}} + +{{/* +Return local licenseKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._licenseKey" -}} +{{- if .Values.licenseKey -}} + {{- .Values.licenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.licenseKey -}} + {{- .Values.global.licenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the License Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretName" -}} +{{- if .Values.customSecretName -}} + {{- .Values.customSecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretName -}} + {{- .Values.global.customSecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretKey" -}} +{{- if .Values.customSecretLicenseKey -}} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_license_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_license_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the license key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.license.secret" }} +{{- if not (include "newrelic.common.license._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.license._licenseKey" .) }} + {{- fail "You must specify a licenseKey or a customSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.license.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.license.secretKeyName" . }}: {{ include "newrelic.common.license._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_low-data-mode.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_low-data-mode.tpl @@ -0,0 +1,26 @@ +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..19fa92648 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_naming.tpl @@ -0,0 +1,73 @@ +{{/* +This is an function to be called directly with a string just to truncate strings to +63 chars because some Kubernetes name fields are limited to that. +*/}} +{{- define "newrelic.common.naming.truncateToDNS" -}} +{{- . | trunc 63 | trimSuffix "-" }} +{{- end }} + + + +{{- /* +Given a name and a suffix returns a 'DNS Valid' which always include the suffix, truncating the name if needed. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If suffix is too long it gets truncated but it always takes precedence over name, so a 63 chars suffix would suppress the name. +Usage: +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "" "suffix" "my-suffix" ) }} +*/ -}} +{{- define "newrelic.common.naming.truncateToDNSWithSuffix" -}} +{{- $suffix := (include "newrelic.common.naming.truncateToDNS" .suffix) -}} +{{- $maxLen := (max (sub 63 (add1 (len $suffix))) 0) -}} {{- /* We prepend "-" to the suffix so an additional character is needed */ -}} + +{{- $newName := .name | trunc ($maxLen | int) | trimSuffix "-" -}} +{{- if $newName -}} +{{- printf "%s-%s" $newName $suffix -}} +{{- else -}} +{{ $suffix }} +{{- end -}} + +{{- end -}} + + + +{{/* +Expand the name of the chart. +Uses the Chart name by default if nameOverride is not set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.name" -}} +{{- $name := .Values.nameOverride | default .Chart.Name -}} +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end }} + + + +{{/* +Create a default fully qualified app name. +By default the full name will be "" just in if it has the chart name included in that, if not +it will be concatenated like "-". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.fullname" -}} +{{- $name := include "newrelic.common.naming.name" . -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} + +{{- end -}} + + + +{{/* +Create chart name and version as used by the chart label. +This function should not be used for naming objects. Use "common.naming.{name,fullname}" instead. +*/}} +{{- define "newrelic.common.naming.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_nodeselector.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_nodeselector.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod nodeSelector */ -}} +{{- define "newrelic.common.nodeSelector" -}} + {{- if .Values.nodeSelector -}} + {{- toYaml .Values.nodeSelector -}} + {{- else if .Values.global -}} + {{- if .Values.global.nodeSelector -}} + {{- toYaml .Values.global.nodeSelector -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_priority-class-name.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_priority-class-name.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the pod priorityClassName */ -}} +{{- define "newrelic.common.priorityClassName" -}} + {{- if .Values.priorityClassName -}} + {{- .Values.priorityClassName -}} + {{- else if .Values.global -}} + {{- if .Values.global.priorityClassName -}} + {{- .Values.global.priorityClassName -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_privileged.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_privileged.tpl @@ -0,0 +1,28 @@ +{{- /* +This is a helper that returns whether the chart should assume the user is fine deploying privileged pods. +*/ -}} +{{- define "newrelic.common.privileged" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists. */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values "privileged" | kindIs "bool" -}} + {{- if .Values.privileged -}} + {{- .Values.privileged -}} + {{- end -}} +{{- else if get $global "privileged" | kindIs "bool" -}} + {{- if $global.privileged -}} + {{- $global.privileged -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* Return directly "true" or "false" based in the exist of "newrelic.common.privileged" */ -}} +{{- define "newrelic.common.privileged.value" -}} +{{- if include "newrelic.common.privileged" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_proxy.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_proxy.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the proxy */ -}} +{{- define "newrelic.common.proxy" -}} + {{- if .Values.proxy -}} + {{- .Values.proxy -}} + {{- else if .Values.global -}} + {{- if .Values.global.proxy -}} + {{- .Values.global.proxy -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_security-context.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_security-context.tpl @@ -0,0 +1,23 @@ +{{- /* Defines the container securityContext context */ -}} +{{- define "newrelic.common.securityContext.container" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.containerSecurityContext -}} + {{- toYaml .Values.containerSecurityContext -}} +{{- else if $global.containerSecurityContext -}} + {{- toYaml $global.containerSecurityContext -}} +{{- end -}} +{{- end -}} + + + +{{- /* Defines the pod securityContext context */ -}} +{{- define "newrelic.common.securityContext.pod" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.podSecurityContext -}} + {{- toYaml .Values.podSecurityContext -}} +{{- else if $global.podSecurityContext -}} + {{- toYaml $global.podSecurityContext -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_serviceaccount.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..2d352f6ea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_serviceaccount.tpl @@ -0,0 +1,90 @@ +{{- /* Defines if the service account has to be created or not */ -}} +{{- define "newrelic.common.serviceAccount.create" -}} +{{- $valueFound := false -}} + +{{- /* Look for a global creation of a service account */ -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "create" | kindIs "bool") -}} + {{- $valueFound = true -}} + {{- if .Values.serviceAccount.create -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.serviceAccount.name" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.serviceAccount.create -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Look for a local creation of a service account */ -}} +{{- if not $valueFound -}} + {{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} + {{- $global := index .Values "global" | default dict -}} + {{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "create" | kindIs "bool" -}} + {{- $valueFound = true -}} + {{- if $global.serviceAccount.create -}} + {{- $global.serviceAccount.create -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* In case no serviceAccount value has been found, default to "true" */ -}} +{{- if not $valueFound -}} +true +{{- end -}} +{{- end -}} + + + +{{- /* Defines the name of the service account */ -}} +{{- define "newrelic.common.serviceAccount.name" -}} +{{- $localServiceAccount := "" -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "name" | kindIs "string") -}} + {{- $localServiceAccount = .Values.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := "" -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "name" | kindIs "string" -}} + {{- $globalServiceAccount = $global.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- if (include "newrelic.common.serviceAccount.create" .) -}} + {{- $localServiceAccount | default $globalServiceAccount | default (include "newrelic.common.naming.fullname" .) -}} +{{- else -}} + {{- $localServiceAccount | default $globalServiceAccount | default "default" -}} +{{- end -}} +{{- end -}} + + + +{{- /* Merge the global and local annotations for the service account */ -}} +{{- define "newrelic.common.serviceAccount.annotations" -}} +{{- $localServiceAccount := dict -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if get .Values.serviceAccount "annotations" -}} + {{- $localServiceAccount = .Values.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := dict -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "annotations" -}} + {{- $globalServiceAccount = $global.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $merged := mustMergeOverwrite $globalServiceAccount $localServiceAccount -}} + +{{- if $merged -}} + {{- toYaml $merged -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_staging.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_staging.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the nrStaging toggle. +This helper allows to override the global `.global.nrStaging` with the value of `.nrStaging`. +Returns "true" if `nrStaging` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.nrStaging" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "nrStaging" | kindIs "bool") -}} + {{- if .Values.nrStaging -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.nrStaging" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.nrStaging -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "nrStaging" | kindIs "bool" -}} + {{- if $global.nrStaging -}} + {{- $global.nrStaging -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Returns "true" of "false" directly instead of empty string (Helm falsiness) based on the exit of "newrelic.common.nrStaging" +*/ -}} +{{- define "newrelic.common.nrStaging.value" -}} +{{- if include "newrelic.common.nrStaging" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_tolerations.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_tolerations.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod tolerations */ -}} +{{- define "newrelic.common.tolerations" -}} + {{- if .Values.tolerations -}} + {{- toYaml .Values.tolerations -}} + {{- else if .Values.global -}} + {{- if .Values.global.tolerations -}} + {{- toYaml .Values.global.tolerations -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_verbose-log.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/templates/_verbose-log.tpl @@ -0,0 +1,54 @@ +{{- /* +Abstraction of the verbose toggle. +This helper allows to override the global `.global.verboseLog` with the value of `.verboseLog`. +Returns "true" if `verbose` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.verboseLog" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "verboseLog" | kindIs "bool") -}} + {{- if .Values.verboseLog -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.verboseLog" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.verboseLog -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "verboseLog" | kindIs "bool" -}} + {{- if $global.verboseLog -}} + {{- $global.verboseLog -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return true or false directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsBoolean" -}} +{{- if include "newrelic.common.verboseLog" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return 1 or 0 directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsInt" -}} +{{- if include "newrelic.common.verboseLog" . -}} +1 +{{- else -}} +0 +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/charts/common-library/values.yaml @@ -0,0 +1 @@ +# values are not needed for the library chart, however this file is still needed for helm lint to work. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-bare-minimum-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-bare-minimum-values.yaml new file mode 100644 index 000000000..3fb7df050 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-bare-minimum-values.yaml @@ -0,0 +1,3 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-custom-attributes-as-map.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-custom-attributes-as-map.yaml new file mode 100644 index 000000000..9fec33dc6 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-custom-attributes-as-map.yaml @@ -0,0 +1,12 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + +customAttributes: + test_tag_label: test_tag_value + +image: + kubeEvents: + repository: e2e/nri-kube-events + tag: test + pullPolicy: IfNotPresent diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-custom-attributes-as-string.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-custom-attributes-as-string.yaml new file mode 100644 index 000000000..e12cba339 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-custom-attributes-as-string.yaml @@ -0,0 +1,11 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + +customAttributes: '{"test_tag_label": "test_tag_value"}' + +image: + kubeEvents: + repository: e2e/nri-kube-events + tag: test + pullPolicy: IfNotPresent diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-values.yaml new file mode 100644 index 000000000..4e517d666 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/ci/test-values.yaml @@ -0,0 +1,60 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + +sinks: + # Enable the stdout sink to also see all events in the logs. + stdout: true + # The newRelicInfra sink sends all events to New relic. + newRelicInfra: true + +customAttributes: + test_tag_label: test_tag_value + +config: + accountID: 111 + region: EU + +rbac: + create: true + +serviceAccount: + create: true + +podAnnotations: + annotation1: "annotation" + +nodeSelector: + kubernetes.io/os: linux + +tolerations: + - key: "key1" + effect: "NoSchedule" + operator: "Exists" + +affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + +hostNetwork: true + +dnsConfig: + nameservers: + - 1.2.3.4 + searches: + - my.dns.search.suffix + options: + - name: ndots + value: "1" + +image: + kubeEvents: + repository: e2e/nri-kube-events + tag: test + pullPolicy: IfNotPresent diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/NOTES.txt b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/NOTES.txt new file mode 100644 index 000000000..3fd06b4a2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/NOTES.txt @@ -0,0 +1,3 @@ +{{ include "nri-kube-events.compatibility.message.securityContext.runAsUser" . }} + +{{ include "nri-kube-events.compatibility.message.images" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/_helpers.tpl new file mode 100644 index 000000000..5d0b8d257 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} + +{{- define "nri-kube-events.securityContext.pod" -}} +{{- $defaults := fromYaml ( include "nriKubernetes.securityContext.podDefaults" . ) -}} +{{- $compatibilityLayer := include "nri-kube-events.compatibility.securityContext.pod" . | fromYaml -}} +{{- $commonLibrary := fromYaml ( include "newrelic.common.securityContext.pod" . ) -}} + +{{- $finalSecurityContext := dict -}} +{{- if $commonLibrary -}} + {{- $finalSecurityContext = mustMergeOverwrite $commonLibrary $compatibilityLayer -}} +{{- else -}} + {{- $finalSecurityContext = mustMergeOverwrite $defaults $compatibilityLayer -}} +{{- end -}} +{{- toYaml $finalSecurityContext -}} +{{- end -}} + + + +{{- /* These are the defaults that are used for all the containers in this chart */ -}} +{{- define "nriKubernetes.securityContext.podDefaults" -}} +runAsUser: 1000 +runAsNonRoot: true +{{- end -}} + + + +{{- define "nri-kube-events.securityContext.container" -}} +{{- if include "newrelic.common.securityContext.container" . -}} +{{- include "newrelic.common.securityContext.container" . -}} +{{- else -}} +privileged: false +allowPrivilegeEscalation: false +readOnlyRootFilesystem: true +{{- end -}} +{{- end -}} + + + +{{- /* */ -}} +{{- define "nri-kube-events.agentConfig" -}} +is_forward_only: true +http_server_enabled: true +http_server_port: 8001 +{{ include "newrelic.common.agentConfig.defaults" . }} +{{- end -}} \ No newline at end of file diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/_helpers_compatibility.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/_helpers_compatibility.tpl new file mode 100644 index 000000000..059cfff12 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/_helpers_compatibility.tpl @@ -0,0 +1,262 @@ +{{/* +Returns a dictionary with legacy runAsUser config. +We know that it only has "one line" but it is separated from the rest of the helpers because it is a temporary things +that we should EOL. The EOL time of this will be marked when we GA the deprecation of Helm v2. +*/}} +{{- define "nri-kube-events.compatibility.securityContext.pod" -}} +{{- if .Values.runAsUser -}} +runAsUser: {{ .Values.runAsUser }} +{{- end -}} +{{- end -}} + + + +{{- /* +Functions to get values from the globals instead of the common library +We make this because there could be difficult to see what is going under +the hood if we use the common-library here. So it is easy to read something +like: +{{- $registry := $oldRegistry | default $newRegistry | default $globalRegistry -}} +*/ -}} +{{- define "nri-kube-events.compatibility.global.registry" -}} + {{- if .Values.global -}} + {{- if .Values.global.images -}} + {{- if .Values.global.images.registry -}} + {{- .Values.global.images.registry -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Functions to fetch integration image configuration from the old .Values.image */ -}} +{{- /* integration's old registry */ -}} +{{- define "nri-kube-events.compatibility.old.integration.registry" -}} + {{- if .Values.image -}} + {{- if .Values.image.kubeEvents -}} + {{- if .Values.image.kubeEvents.registry -}} + {{- .Values.image.kubeEvents.registry -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* integration's old repository */ -}} +{{- define "nri-kube-events.compatibility.old.integration.repository" -}} + {{- if .Values.image -}} + {{- if .Values.image.kubeEvents -}} + {{- if .Values.image.kubeEvents.repository -}} + {{- .Values.image.kubeEvents.repository -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* integration's old tag */ -}} +{{- define "nri-kube-events.compatibility.old.integration.tag" -}} + {{- if .Values.image -}} + {{- if .Values.image.kubeEvents -}} + {{- if .Values.image.kubeEvents.tag -}} + {{- .Values.image.kubeEvents.tag -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* integration's old imagePullPolicy */ -}} +{{- define "nri-kube-events.compatibility.old.integration.pullPolicy" -}} + {{- if .Values.image -}} + {{- if .Values.image.kubeEvents -}} + {{- if .Values.image.kubeEvents.pullPolicy -}} + {{- .Values.image.kubeEvents.pullPolicy -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Functions to fetch agent image configuration from the old .Values.image */ -}} +{{- /* agent's old registry */ -}} +{{- define "nri-kube-events.compatibility.old.agent.registry" -}} + {{- if .Values.image -}} + {{- if .Values.image.infraAgent -}} + {{- if .Values.image.infraAgent.registry -}} + {{- .Values.image.infraAgent.registry -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* agent's old repository */ -}} +{{- define "nri-kube-events.compatibility.old.agent.repository" -}} + {{- if .Values.image -}} + {{- if .Values.image.infraAgent -}} + {{- if .Values.image.infraAgent.repository -}} + {{- .Values.image.infraAgent.repository -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* agent's old tag */ -}} +{{- define "nri-kube-events.compatibility.old.agent.tag" -}} + {{- if .Values.image -}} + {{- if .Values.image.infraAgent -}} + {{- if .Values.image.infraAgent.tag -}} + {{- .Values.image.infraAgent.tag -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* agent's old imagePullPolicy */ -}} +{{- define "nri-kube-events.compatibility.old.agent.pullPolicy" -}} + {{- if .Values.image -}} + {{- if .Values.image.infraAgent -}} + {{- if .Values.image.infraAgent.pullPolicy -}} + {{- .Values.image.infraAgent.pullPolicy -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{/* +Creates the image string needed to pull the integration image respecting the breaking change we made in the values file +*/}} +{{- define "nri-kube-events.compatibility.images.integration" -}} +{{- $globalRegistry := include "nri-kube-events.compatibility.global.registry" . -}} +{{- $oldRegistry := include "nri-kube-events.compatibility.old.integration.registry" . -}} +{{- $newRegistry := .Values.images.integration.registry -}} +{{- $registry := $oldRegistry | default $newRegistry | default $globalRegistry -}} + +{{- $oldRepository := include "nri-kube-events.compatibility.old.integration.repository" . -}} +{{- $newRepository := .Values.images.integration.repository -}} +{{- $repository := $oldRepository | default $newRepository }} + +{{- $oldTag := include "nri-kube-events.compatibility.old.integration.tag" . -}} +{{- $newTag := .Values.images.integration.tag -}} +{{- $tag := $oldTag | default $newTag | default .Chart.AppVersion -}} + +{{- if $registry -}} + {{- printf "%s/%s:%s" $registry $repository $tag -}} +{{- else -}} + {{- printf "%s:%s" $repository $tag -}} +{{- end -}} +{{- end -}} + + + +{{/* +Creates the image string needed to pull the agent's image respecting the breaking change we made in the values file +*/}} +{{- define "nri-kube-events.compatibility.images.agent" -}} +{{- $globalRegistry := include "nri-kube-events.compatibility.global.registry" . -}} +{{- $oldRegistry := include "nri-kube-events.compatibility.old.agent.registry" . -}} +{{- $newRegistry := .Values.images.agent.registry -}} +{{- $registry := $oldRegistry | default $newRegistry | default $globalRegistry -}} + +{{- $oldRepository := include "nri-kube-events.compatibility.old.agent.repository" . -}} +{{- $newRepository := .Values.images.agent.repository -}} +{{- $repository := $oldRepository | default $newRepository }} + +{{- $oldTag := include "nri-kube-events.compatibility.old.agent.tag" . -}} +{{- $newTag := .Values.images.agent.tag -}} +{{- $tag := $oldTag | default $newTag -}} + +{{- if $registry -}} + {{- printf "%s/%s:%s" $registry $repository $tag -}} +{{- else -}} + {{- printf "%s:%s" $repository $tag -}} +{{- end -}} +{{- end -}} + + + +{{/* +Returns the pull policy for the integration image taking into account that we made a breaking change on the values path. +*/}} +{{- define "nri-kube-events.compatibility.images.pullPolicy.integration" -}} +{{- $old := include "nri-kube-events.compatibility.old.integration.pullPolicy" . -}} +{{- $new := .Values.images.integration.pullPolicy -}} + +{{- $old | default $new -}} +{{- end -}} + + + +{{/* +Returns the pull policy for the agent image taking into account that we made a breaking change on the values path. +*/}} +{{- define "nri-kube-events.compatibility.images.pullPolicy.agent" -}} +{{- $old := include "nri-kube-events.compatibility.old.agent.pullPolicy" . -}} +{{- $new := .Values.images.agent.pullPolicy -}} + +{{- $old | default $new -}} +{{- end -}} + + + +{{/* +Returns a merged list of pull secrets ready to be used +*/}} +{{- define "nri-kube-events.compatibility.images.renderPullSecrets" -}} +{{- $list := list -}} + +{{- if .Values.image -}} + {{- if .Values.image.pullSecrets -}} + {{- $list = append $list .Values.image.pullSecrets }} + {{- end -}} +{{- end -}} + +{{- if .Values.images.pullSecrets -}} + {{- $list = append $list .Values.images.pullSecrets -}} +{{- end -}} + +{{- include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" $list "context" .) }} +{{- end -}} + + + +{{- /* Messege to show to the user saying that image value is not supported anymore */ -}} +{{- define "nri-kube-events.compatibility.message.images" -}} +{{- $oldIntegrationRegistry := include "nri-kube-events.compatibility.old.integration.registry" . -}} +{{- $oldIntegrationRepository := include "nri-kube-events.compatibility.old.integration.repository" . -}} +{{- $oldIntegrationTag := include "nri-kube-events.compatibility.old.integration.tag" . -}} +{{- $oldIntegrationPullPolicy := include "nri-kube-events.compatibility.old.integration.pullPolicy" . -}} +{{- $oldAgentRegistry := include "nri-kube-events.compatibility.old.agent.registry" . -}} +{{- $oldAgentRepository := include "nri-kube-events.compatibility.old.agent.repository" . -}} +{{- $oldAgentTag := include "nri-kube-events.compatibility.old.agent.tag" . -}} +{{- $oldAgentPullPolicy := include "nri-kube-events.compatibility.old.agent.pullPolicy" . -}} + +{{- if or $oldIntegrationRegistry $oldIntegrationRepository $oldIntegrationTag $oldIntegrationPullPolicy $oldAgentRegistry $oldAgentRepository $oldAgentTag $oldAgentPullPolicy }} +Configuring image repository an tag under 'image' is no longer supported. +This is the list values that we no longer support: + - image.kubeEvents.registry + - image.kubeEvents.repository + - image.kubeEvents.tag + - image.kubeEvents.pullPolicy + - image.infraAgent.registry + - image.infraAgent.repository + - image.infraAgent.tag + - image.infraAgent.pullPolicy + +Please set: + - images.agent.* to configure the infrastructure-agent forwarder. + - images.integration.* to configure the image in charge of scraping k8s data. + +------ +{{- end }} +{{- end -}} + + + +{{- /* Messege to show to the user saying that image value is not supported anymore */ -}} +{{- define "nri-kube-events.compatibility.message.securityContext.runAsUser" -}} +{{- if .Values.runAsUser }} +WARNING: `runAsUser` is deprecated +================================== + +We have automatically translated your `runAsUser` setting to the new format, but this shimming will be removed in the +future. Please migrate your configs to the new format in the `securityContext` key. +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/agent-configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/agent-configmap.yaml new file mode 100644 index 000000000..02bf8306b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/agent-configmap.yaml @@ -0,0 +1,12 @@ +{{- if .Values.sinks.newRelicInfra -}} +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.naming.fullname" . }}-agent-config + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: | + {{- include "nri-kube-events.agentConfig" . | nindent 4 }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/clusterrole.yaml new file mode 100644 index 000000000..cbfd5d9ce --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/clusterrole.yaml @@ -0,0 +1,42 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.naming.fullname" . }} +rules: +- apiGroups: + - "" + resources: + - events + - namespaces + - nodes + - jobs + - persistentvolumes + - persistentvolumeclaims + - pods + - services + verbs: + - get + - watch + - list +- apiGroups: + - apps + resources: + - daemonsets + - deployments + verbs: + - get + - watch + - list +- apiGroups: + - batch + resources: + - cronjobs + - jobs + verbs: + - get + - watch + - list +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..fc5dfb8da --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.naming.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic.common.naming.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/configmap.yaml new file mode 100644 index 000000000..9e4e35f6b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/configmap.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.naming.fullname" . }}-config + namespace: {{ .Release.Namespace }} +data: + config.yaml: |- + sinks: + {{- if .Values.sinks.stdout }} + - name: stdout + {{- end }} + {{- if .Values.sinks.newRelicInfra }} + - name: newRelicInfra + config: + agentEndpoint: http://localhost:8001/v1/data + clusterName: {{ include "newrelic.common.cluster" . }} + agentHTTPTimeout: {{ .Values.agentHTTPTimeout }} + {{- end }} + captureDescribe: {{ .Values.scrapers.descriptions.enabled }} + describeRefresh: {{ .Values.scrapers.descriptions.resyncPeriod | default "24h" }} + captureEvents: {{ .Values.scrapers.events.enabled }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/deployment.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/deployment.yaml new file mode 100644 index 000000000..7ba9eaea9 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/deployment.yaml @@ -0,0 +1,124 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + annotations: + {{- if .Values.deployment.annotations }} + {{- toYaml .Values.deployment.annotations | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ include "newrelic.common.naming.name" . }} + template: + metadata: + {{- if .Values.podAnnotations }} + annotations: + {{- toYaml .Values.podAnnotations | nindent 8}} + {{- end }} + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} + spec: + {{- with include "nri-kube-events.compatibility.images.renderPullSecrets" . }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + {{- with include "nri-kube-events.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + containers: + - name: kube-events + image: {{ include "nri-kube-events.compatibility.images.integration" . }} + imagePullPolicy: {{ include "nri-kube-events.compatibility.images.pullPolicy.integration" . }} + {{- with include "nri-kube-events.securityContext.container" . }} + securityContext: + {{- . | nindent 12 }} + {{- end }} + {{- if .Values.resources }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + args: ["-config", "/app/config/config.yaml", "-loglevel", "debug"] + volumeMounts: + - name: config-volume + mountPath: /app/config + {{- if .Values.sinks.newRelicInfra }} + - name: forwarder + image: {{ include "nri-kube-events.compatibility.images.agent" . }} + imagePullPolicy: {{ include "nri-kube-events.compatibility.images.pullPolicy.agent" . }} + {{- with include "nri-kube-events.securityContext.container" . }} + securityContext: + {{- . | nindent 12 }} + {{- end }} + ports: + - containerPort: {{ get (fromYaml (include "nri-kube-events.agentConfig" .)) "http_server_port" }} + env: + - name: NRIA_LICENSE_KEY + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} + + - name: NRIA_OVERRIDE_HOSTNAME_SHORT + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: spec.nodeName + + volumeMounts: + - mountPath: /var/db/newrelic-infra/data + name: tmpfs-data + - mountPath: /var/db/newrelic-infra/user_data + name: tmpfs-user-data + - mountPath: /tmp + name: tmpfs-tmp + - name: config + mountPath: /etc/newrelic-infra.yml + subPath: newrelic-infra.yml + {{- if ((.Values.forwarder).resources) }} + resources: + {{- toYaml .Values.forwarder.resources | nindent 12 }} + {{- end }} + {{- end }} + serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} + volumes: + {{- if .Values.sinks.newRelicInfra }} + - name: config + configMap: + name: {{ include "newrelic.common.naming.fullname" . }}-agent-config + items: + - key: newrelic-infra.yml + path: newrelic-infra.yml + {{- end }} + - name: config-volume + configMap: + name: {{ include "newrelic.common.naming.fullname" . }}-config + - name: tmpfs-data + emptyDir: {} + - name: tmpfs-user-data + emptyDir: {} + - name: tmpfs-tmp + emptyDir: {} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 8 }} + {{- end }} + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/secret.yaml new file mode 100644 index 000000000..f558ee86c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/secret.yaml @@ -0,0 +1,2 @@ +{{- /* Common library will take care of creating the secret or not. */}} +{{- include "newrelic.common.license.secret" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/serviceaccount.yaml new file mode 100644 index 000000000..07e818da0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +{{- if include "newrelic.common.serviceAccount.create" . }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} + annotations: +{{ include "newrelic.common.serviceAccount.annotations" . | indent 4 }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/agent_configmap_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/agent_configmap_test.yaml new file mode 100644 index 000000000..831b0c5aa --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/agent_configmap_test.yaml @@ -0,0 +1,46 @@ +suite: test configmap for newrelic infra agent +templates: + - templates/agent-configmap.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: has the correct default values + set: + cluster: test-cluster + licenseKey: us-whatever + asserts: + - equal: + path: data["newrelic-infra.yml"] + value: | + is_forward_only: true + http_server_enabled: true + http_server_port: 8001 + + - it: integrates properly with the common library + set: + cluster: test-cluster + licenseKey: us-whatever + fedramp.enabled: true + verboseLog: true + asserts: + - equal: + path: data["newrelic-infra.yml"] + value: | + is_forward_only: true + http_server_enabled: true + http_server_port: 8001 + + log: + level: trace + fedramp: true + + - it: does not template if the http sink is disabled + set: + cluster: test-cluster + licenseKey: us-whatever + sinks: + newRelicInfra: false + asserts: + - hasDocuments: + count: 0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/configmap_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/configmap_test.yaml new file mode 100644 index 000000000..68ad53a57 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/configmap_test.yaml @@ -0,0 +1,139 @@ +suite: test configmap for sinks +templates: + - templates/configmap.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: has the correct sinks when default values used + set: + licenseKey: us-whatever + cluster: a-cluster + asserts: + - equal: + path: data["config.yaml"] + value: |- + sinks: + - name: newRelicInfra + config: + agentEndpoint: http://localhost:8001/v1/data + clusterName: a-cluster + agentHTTPTimeout: 30s + captureDescribe: true + describeRefresh: 24h + captureEvents: true + + - it: honors agentHTTPTimeout + set: + licenseKey: us-whatever + cluster: a-cluster + agentHTTPTimeout: 10s + asserts: + - equal: + path: data["config.yaml"] + value: |- + sinks: + - name: newRelicInfra + config: + agentEndpoint: http://localhost:8001/v1/data + clusterName: a-cluster + agentHTTPTimeout: 10s + captureDescribe: true + describeRefresh: 24h + captureEvents: true + + - it: has the correct sinks defined in local values + set: + licenseKey: us-whatever + cluster: a-cluster + sinks: + stdout: true + newRelicInfra: false + asserts: + - equal: + path: data["config.yaml"] + value: |- + sinks: + - name: stdout + captureDescribe: true + describeRefresh: 24h + captureEvents: true + + - it: allows enabling/disabling event scraping + set: + licenseKey: us-whatever + cluster: a-cluster + scrapers: + events: + enabled: false + asserts: + - equal: + path: data["config.yaml"] + value: |- + sinks: + - name: newRelicInfra + config: + agentEndpoint: http://localhost:8001/v1/data + clusterName: a-cluster + agentHTTPTimeout: 30s + captureDescribe: true + describeRefresh: 24h + captureEvents: false + + - it: allows enabling/disabling description scraping + set: + licenseKey: us-whatever + cluster: a-cluster + scrapers: + descriptions: + enabled: false + asserts: + - equal: + path: data["config.yaml"] + value: |- + sinks: + - name: newRelicInfra + config: + agentEndpoint: http://localhost:8001/v1/data + clusterName: a-cluster + agentHTTPTimeout: 30s + captureDescribe: false + describeRefresh: 24h + captureEvents: true + + - it: allows changing description resync intervals + set: + licenseKey: us-whatever + cluster: a-cluster + scrapers: + descriptions: + resyncPeriod: 4h + asserts: + - equal: + path: data["config.yaml"] + value: |- + sinks: + - name: newRelicInfra + config: + agentEndpoint: http://localhost:8001/v1/data + clusterName: a-cluster + agentHTTPTimeout: 30s + captureDescribe: true + describeRefresh: 4h + captureEvents: true + + - it: has another document generated with the proper config set + set: + licenseKey: us-whatever + cluster: a-cluster + sinks: + stdout: false + newRelicInfra: false + asserts: + - equal: + path: data["config.yaml"] + value: |- + sinks: + captureDescribe: true + describeRefresh: 24h + captureEvents: true diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/deployment_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/deployment_test.yaml new file mode 100644 index 000000000..702917bce --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/deployment_test.yaml @@ -0,0 +1,104 @@ +suite: test deployment images +templates: + - templates/deployment.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: deployment image uses pullSecrets + set: + cluster: my-cluster + licenseKey: us-whatever + images: + pullSecrets: + - name: regsecret + asserts: + - equal: + path: spec.template.spec.imagePullSecrets + value: + - name: regsecret + + - it: deployment images use the proper image tag + set: + cluster: test-cluster + licenseKey: us-whatever + images: + integration: + repository: newrelic/nri-kube-events + tag: "latest" + agent: + repository: newrelic/k8s-events-forwarder + tag: "latest" + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: .*newrelic/nri-kube-events:latest$ + - matchRegex: + path: spec.template.spec.containers[1].image + pattern: .*newrelic/k8s-events-forwarder:latest$ + + + - it: by default the agent forwarder templates + set: + cluster: test-cluster + licenseKey: us-whatever + asserts: + - contains: + path: spec.template.spec.containers + any: true + content: + name: forwarder + - contains: + path: spec.template.spec.volumes + content: + name: config + configMap: + name: my-release-nri-kube-events-agent-config + items: + - key: newrelic-infra.yml + path: newrelic-infra.yml + + - it: agent does not template if the sink is disabled + set: + cluster: test-cluster + licenseKey: us-whatever + sinks: + newRelicInfra: false + asserts: + - notContains: + path: spec.template.spec.containers + any: true + content: + name: forwarder + - notContains: + path: spec.template.spec.volumes + content: + name: config + configMap: + name: my-release-nri-kube-events-agent-config + items: + - key: newrelic-infra.yml + path: newrelic-infra.yml + + - it: has a linux node selector by default + set: + cluster: my-cluster + licenseKey: us-whatever + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + + - it: has a linux node selector and additional selectors + set: + cluster: my-cluster + licenseKey: us-whatever + nodeSelector: + aCoolTestLabel: aCoolTestValue + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + aCoolTestLabel: aCoolTestValue diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/images_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/images_test.yaml new file mode 100644 index 000000000..361be582b --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/images_test.yaml @@ -0,0 +1,168 @@ +suite: test image compatibility layer +templates: + - templates/deployment.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: by default the tag is not nil + set: + cluster: test-cluster + licenseKey: us-whatever + asserts: + - notMatchRegex: + path: spec.template.spec.containers[0].image + pattern: ".*nil.*" + - notMatchRegex: + path: spec.template.spec.containers[1].image + pattern: ".*nil.*" + + - it: templates image correctly from the new values + set: + cluster: test-cluster + licenseKey: us-whatever + images: + integration: + registry: ireg + repository: irep + tag: itag + agent: + registry: areg + repository: arep + tag: atag + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: ireg/irep:itag + - equal: + path: spec.template.spec.containers[1].image + value: areg/arep:atag + + - it: templates image correctly from old values + set: + cluster: test-cluster + licenseKey: us-whatever + image: + kubeEvents: + registry: ireg + repository: irep + tag: itag + infraAgent: + registry: areg + repository: arep + tag: atag + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: ireg/irep:itag + - equal: + path: spec.template.spec.containers[1].image + value: areg/arep:atag + + - it: old image values take precedence + set: + cluster: test-cluster + licenseKey: us-whatever + images: + integration: + registry: inew + repository: inew + tag: inew + agent: + registry: anew + repository: anew + tag: anew + image: + kubeEvents: + registry: iold + repository: iold + tag: iold + infraAgent: + registry: aold + repository: aold + tag: aold + asserts: + - equal: + path: spec.template.spec.containers[0].image + value: iold/iold:iold + - equal: + path: spec.template.spec.containers[1].image + value: aold/aold:aold + + - it: pullImagePolicy templates correctly from the new values + set: + cluster: test-cluster + licenseKey: us-whatever + images: + integration: + pullPolicy: new + agent: + pullPolicy: new + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: new + - equal: + path: spec.template.spec.containers[1].imagePullPolicy + value: new + + - it: pullImagePolicy templates correctly from old values + set: + cluster: test-cluster + licenseKey: us-whatever + image: + kubeEvents: + pullPolicy: old + infraAgent: + pullPolicy: old + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: old + - equal: + path: spec.template.spec.containers[1].imagePullPolicy + value: old + + - it: old imagePullPolicy values take precedence + set: + cluster: test-cluster + licenseKey: us-whatever + images: + integration: + pullPolicy: new + agent: + pullPolicy: new + image: + kubeEvents: + pullPolicy: old + infraAgent: + pullPolicy: old + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: old + - equal: + path: spec.template.spec.containers[1].imagePullPolicy + value: old + + - it: imagePullSecrets merge properly + set: + cluster: test-cluster + licenseKey: us-whatever + global: + images: + pullSecrets: + - global: global + images: + pullSecrets: + - images: images + image: + pullSecrets: + - image: image + asserts: + - equal: + path: spec.template.spec.imagePullSecrets + value: + - global: global + - image: image + - images: images diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/security_context_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/security_context_test.yaml new file mode 100644 index 000000000..b2b710331 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/tests/security_context_test.yaml @@ -0,0 +1,77 @@ +suite: test deployment security context +templates: + - templates/deployment.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: pod securityContext set to defaults when no values provided + set: + cluster: my-cluster + licenseKey: us-whatever + asserts: + - equal: + path: spec.template.spec.securityContext + value: + runAsUser: 1000 + runAsNonRoot: true + - it: pod securityContext set common-library values + set: + cluster: test-cluster + licenseKey: us-whatever + podSecurityContext: + foobar: true + asserts: + - equal: + path: spec.template.spec.securityContext.foobar + value: true + - it: pod securityContext compatibility layer overrides values from common-library + set: + cluster: test-cluster + licenseKey: us-whatever + runAsUser: 1001 + podSecurityContext: + runAsUser: 1000 + runAsNonRoot: false + asserts: + - equal: + path: spec.template.spec.securityContext + value: + runAsUser: 1001 + runAsNonRoot: false + - it: pod securityContext compatibility layer overrides defaults + set: + cluster: test-cluster + licenseKey: us-whatever + runAsUser: 1001 + asserts: + - equal: + path: spec.template.spec.securityContext.runAsUser + value: 1001 + - it: set to defaults when no containerSecurityContext set + set: + cluster: my-cluster + licenseKey: us-whatever + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext + value: + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: true + - equal: + path: spec.template.spec.containers[1].securityContext + value: + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: true + - it: set containerSecurityContext custom values + set: + cluster: test-cluster + licenseKey: us-whatever + containerSecurityContext: + foobar: true + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.foobar + value: true diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/values.yaml new file mode 100644 index 000000000..f0d5fbe20 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-kube-events/values.yaml @@ -0,0 +1,135 @@ +# -- Override the name of the chart +nameOverride: "" +# -- Override the full name of the release +fullnameOverride: "" + +# -- Name of the Kubernetes cluster monitored. Mandatory. Can be configured also with `global.cluster` +cluster: "" +# -- This set this license key to use. Can be configured also with `global.licenseKey` +licenseKey: "" +# -- In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` +customSecretName: "" +# -- In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` +customSecretLicenseKey: "" + +# -- Images used by the chart for the integration and agents +# @default -- See `values.yaml` +images: + # -- Image for the New Relic Kubernetes integration + # @default -- See `values.yaml` + integration: + registry: + repository: newrelic/nri-kube-events + tag: + pullPolicy: IfNotPresent + # -- Image for the New Relic Infrastructure Agent sidecar + # @default -- See `values.yaml` + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.53.0 + pullPolicy: IfNotPresent + # -- The secrets that are needed to pull images from a custom registry. + pullSecrets: [] + # - name: regsecret + +# -- Resources for the integration container +resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# -- Resources for the forwarder sidecar container +forwarder: + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +rbac: + # -- Specifies whether RBAC resources should be created + create: true + +# -- Settings controlling ServiceAccount creation +# @default -- See `values.yaml` +serviceAccount: + # serviceAccount.create -- (bool) Specifies whether a ServiceAccount should be created + # @default -- `true` + create: + # If not set and create is true, a name is generated using the fullname template + name: "" + # Specify any annotations to add to the ServiceAccount + annotations: + +# -- Annotations to add to the pod. +podAnnotations: {} +deployment: + # deployment.annotations -- Annotations to add to the Deployment. + annotations: {} +# -- Additional labels for chart pods +podLabels: {} +# -- Additional labels for chart objects +labels: {} + +# -- Amount of time to wait until timeout to send metrics to the metric forwarder +agentHTTPTimeout: "30s" + +# -- Configure where will the metrics be written. Mostly for debugging purposes. +# @default -- See `values.yaml` +sinks: + # -- Enable the stdout sink to also see all events in the logs. + stdout: false + # -- The newRelicInfra sink sends all events to New Relic. + newRelicInfra: true + +# -- Configure the various kinds of scrapers that should be run. +# @default -- See `values.yaml` +scrapers: + descriptions: + enabled: true + resyncPeriod: "24h" + events: + enabled: true + +# -- Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` +priorityClassName: "" +# -- (bool) Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` +# @default -- `false` +hostNetwork: +# -- Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` +dnsConfig: {} +# -- Sets security context (at pod level). Can be configured also with `global.podSecurityContext` +podSecurityContext: {} +# -- Sets security context (at container level). Can be configured also with `global.containerSecurityContext` +containerSecurityContext: {} + +# -- Sets pod/node affinities. Can be configured also with `global.affinity` +affinity: {} +# -- Sets pod's node selector. Can be configured also with `global.nodeSelector` +nodeSelector: {} +# -- Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` +tolerations: [] + +# -- Adds extra attributes to the cluster and all the metrics emitted to the backend. Can be configured also with `global.customAttributes` +customAttributes: {} + +# -- Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port`. Can be configured also with `global.proxy` +proxy: "" + +# -- (bool) Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` +# @default -- `false` +nrStaging: +fedramp: + # -- (bool) Enables FedRAMP. Can be configured also with `global.fedramp.enabled` + # @default -- `false` + enabled: + +# -- (bool) Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` +# @default -- `false` +verboseLog: diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/.helmignore new file mode 100644 index 000000000..f62b5519e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/.helmignore @@ -0,0 +1 @@ +templates/admission-webhooks/job-patch/README.md diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/Chart.lock new file mode 100644 index 000000000..c65e88efd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +digest: sha256:fa87cb007564a39a72739a3e850a91d6b03c0fc27a1115deac042b3ef77b4142 +generated: "2024-06-21T17:31:31.266100576Z" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/Chart.yaml new file mode 100644 index 000000000..e627e6732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +appVersion: 1.28.2 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +description: A Helm chart to deploy the New Relic metadata injection webhook. +home: https://hub.docker.com/r/newrelic/k8s-metadata-injection +icon: https://newrelic.com/assets/newrelic/source/NewRelic-logo-square.svg +keywords: +- infrastructure +- newrelic +- monitoring +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +name: nri-metadata-injection +sources: +- https://github.com/newrelic/k8s-metadata-injection +- https://github.com/newrelic/k8s-metadata-injection/tree/master/charts/nri-metadata-injection +version: 4.20.2 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/README.md new file mode 100644 index 000000000..dd922ef13 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/README.md @@ -0,0 +1,68 @@ +# nri-metadata-injection + +A Helm chart to deploy the New Relic metadata injection webhook. + +**Homepage:** + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add nri-metadata-injection https://newrelic.github.io/k8s-metadata-injection +helm upgrade --install nri-metadata-injection/nri-metadata-injection -f your-custom-values.yaml +``` + +## Source Code + +* +* + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Sets pod/node affinities. Can be configured also with `global.affinity` | +| certManager.enabled | bool | `false` | Use cert manager for webhook certs | +| certManager.rootCertificateDuration | string | `"43800h"` | Sets the root certificate duration. Defaults to 43800h (5 years). | +| certManager.webhookCertificateDuration | string | `"8760h"` | Sets certificate duration. Defaults to 8760h (1 year). | +| cluster | string | `""` | Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster` | +| containerSecurityContext | object | `{}` | Sets security context (at container level). Can be configured also with `global.containerSecurityContext` | +| customTLSCertificate | bool | `false` | Use custom tls certificates for the webhook, or let the chart handle it automatically. Ref: https://docs.newrelic.com/docs/integrations/kubernetes-integration/link-your-applications/link-your-applications-kubernetes#configure-injection | +| dnsConfig | object | `{}` | Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` | +| fullnameOverride | string | `""` | Override the full name of the release | +| hostNetwork | bool | false | Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` | +| image | object | See `values.yaml` | Image for the New Relic Metadata Injector | +| image.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | +| injectOnlyLabeledNamespaces | bool | `false` | Enable the metadata decoration only for pods living in namespaces labeled with 'newrelic-metadata-injection=enabled'. | +| jobImage | object | See `values.yaml` | Image for creating the needed certificates of this webhook to work | +| jobImage.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | +| jobImage.volumeMounts | list | `[]` | Volume mounts to add to the job, you might want to mount tmp if Pod Security Policies Enforce a read-only root. | +| jobImage.volumes | list | `[]` | Volumes to add to the job container | +| labels | object | `{}` | Additional labels for chart objects. Can be configured also with `global.labels` | +| nameOverride | string | `""` | Override the name of the chart | +| nodeSelector | object | `{}` | Sets pod's node selector. Can be configured also with `global.nodeSelector` | +| podAnnotations | object | `{}` | Annotations to be added to all pods created by the integration. | +| podLabels | object | `{}` | Additional labels for chart pods. Can be configured also with `global.podLabels` | +| podSecurityContext | object | `{}` | Sets security context (at pod level). Can be configured also with `global.podSecurityContext` | +| priorityClassName | string | `""` | Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` | +| rbac.pspEnabled | bool | `false` | Whether the chart should create Pod Security Policy objects. | +| replicas | int | `1` | | +| resources | object | 100m/30M -/80M | Image for creating the needed certificates of this webhook to work | +| timeoutSeconds | int | `28` | Webhook timeout Ref: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts | +| tolerations | list | `[]` | Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` | + +## Maintainers + +* [juanjjaramillo](https://github.com/juanjjaramillo) +* [csongnr](https://github.com/csongnr) +* [dbudziwojskiNR](https://github.com/dbudziwojskiNR) diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/README.md.gotmpl new file mode 100644 index 000000000..752ba8aae --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/README.md.gotmpl @@ -0,0 +1,41 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add nri-metadata-injection https://newrelic.github.io/k8s-metadata-injection +helm upgrade --install nri-metadata-injection/nri-metadata-injection -f your-custom-values.yaml +``` + +{{ template "chart.sourcesSection" . }} + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +{{ template "chart.valuesSection" . }} + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/Chart.yaml new file mode 100644 index 000000000..b65ac15d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +- name: kang-makes + url: https://github.com/kang-makes +name: common-library +type: library +version: 1.2.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/DEVELOPERS.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/DEVELOPERS.md new file mode 100644 index 000000000..3ccc108e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/DEVELOPERS.md @@ -0,0 +1,663 @@ +# Functions/templates documented for chart writers +Here is some rough documentation separated by the file that contains the function, the function +name and how to use it. We are not covering functions that start with `_` (e.g. +`newrelic.common.license._licenseKey`) because they are used internally by this library for +other helpers. Helm does not have the concept of "public" or "private" functions/templates so +this is a convention of ours. + +## _naming.tpl +These functions are used to name objects. + +### `newrelic.common.naming.name` +This is the same as the idiomatic `CHART-NAME.name` that is created when you use `helm create`. + +It honors `.Values.nameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.name" . }} +``` + +### `newrelic.common.naming.fullname` +This is the same as the idiomatic `CHART-NAME.fullname` that is created when you use `helm create` + +It honors `.Values.fullnameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.fullname" . }} +``` + +### `newrelic.common.naming.chart` +This is the same as the idiomatic `CHART-NAME.chart` that is created when you use `helm create`. + +It is mostly useless for chart writers. It is used internally for templating the labels but there +is no reason to keep it "private". + +Usage: +```mustache +{{ include "newrelic.common.naming.chart" . }} +``` + +### `newrelic.common.naming.truncateToDNS` +This is a useful template that could be used to trim a string to 63 chars and does not end with a dash (`-`). +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $truncatedName := include "newrelic.common.naming.truncateToDNS" $nameToTruncate }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-string-that-should-be */ -}} +``` + +### `newrelic.common.naming.truncateToDNSWithSuffix` +This template function is the same as the above but instead of receiving a string you should give a `dict` +with a `name` and a `suffix`. This function will join them with a dash (`-`) and trim the `name` so the +result of `name-suffix` is no more than 63 chars + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $suffix := "A-NOT-SO-LONG-SUFFIX" }} +{{- $truncatedName := include "truncateToDNSWithSuffix" (dict "name" $nameToTruncate "suffix" $suffix) }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-A-NOT-SO-LONG-SUFFIX */ -}} +``` + + + +## _labels.tpl +### `newrelic.common.labels`, `newrelic.common.labels.selectorLabels` and `newrelic.common.labels.podLabels` +These are functions that are used to label objects. They are configured by this `values.yaml` +```yaml +global: + podLabels: {} # included in all the pods of all the charts that implement this library + labels: {} # included in all the objects of all the charts that implement this library +podLabels: {} # included in all the pods of this chart +labels: {} # included in all the objects of this chart +``` + +label maps are merged from global to local values. + +And chart writer should use them like this: +```mustache +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} +``` + +`newrelic.common.labels.podLabels` includes `newrelic.common.labels.selectorLabels` automatically. + + + +## _priority-class-name.tpl +### `newrelic.common.priorityClassName` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + priorityClassName: "" +priorityClassName: "" +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `priorityClassName` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} +``` + + + +## _hostnetwork.tpl +### `newrelic.common.hostNetwork` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + hostNetwork: # Note that this is empty (nil) +hostNetwork: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `hostNetwork` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.hostNetwork" . }} + hostNetwork: {{ . }} + {{- end }} +``` + +### `newrelic.common.hostNetwork.value` +This function is an abstraction of the function above but this returns directly "true" or "false". + +Be careful with using this with an `if` as Helm does evaluate "false" (string) as `true`. + +Usage (example in a pod spec): +```mustache +spec: + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} +``` + + + +## _dnsconfig.tpl +### `newrelic.common.dnsConfig` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + dnsConfig: {} +dnsConfig: {} +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `dnsConfig` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _images.tpl +These functions help us to deal with how images are templated. This allows setting `registries` +where to fetch images globally while being flexible enough to fit in different maps of images +and deployments with one or more images. This is the example of a complex `values.yaml` that +we are going to use during the documentation of these functions: + +```yaml +global: + images: + registry: nexus-3-instance.internal.clients-domain.tld +jobImage: + registry: # defaults to "example.tld" when empty in these examples + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent + pullSecrets: [] +images: + integration: + registry: + repository: newrelic/nri-kube-events + tag: 1.8.0 + pullPolicy: IfNotPresent + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.22.0 + pullPolicy: IfNotPresent + pullSecrets: [] +``` + +### `newrelic.common.images.image` +This will return a string with the image ready to be downloaded that includes the registry, the image and the tag. +`defaultRegistry` is used to keep `registry` field empty in `values.yaml` so you can override the image using +`global.images.registry`, your local `jobImage.registry` and be able to fallback to a registry that is not `docker.io` +(Or the default repository that the client could have set in the CRI). + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.image" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.registry` +It returns the registry from the global or local values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.registry" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.repository` +It returns the image from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.tag` +It returns the image's tag from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.renderPullSecrets` +If returns a merged map that contains the pull secrets from the global configuration and the local one. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.jobImage.pullSecrets "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +``` + + + +## _serviceaccount.tpl +These functions are used to evaluate if the service account should be created, with which name and add annotations to it. + +The functions that the common library has implemented for service accounts are: +* `newrelic.common.serviceAccount.create` +* `newrelic.common.serviceAccount.name` +* `newrelic.common.serviceAccount.annotations` + +Usage: +```mustache +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +``` + + + +## _affinity.tpl, _nodeselector.tpl and _tolerations.tpl +These three files are almost the same and they follow the idiomatic way of `helm create`. + +Each function also looks if there is a global value like the other helpers. +```yaml +global: + affinity: {} + nodeSelector: {} + tolerations: [] +affinity: {} +nodeSelector: {} +tolerations: [] +``` + +The values here are replaced instead of be merged. If a value at root level is found, the global one is ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _agent-config.tpl +### `newrelic.common.agentConfig.defaults` +This returns a YAML that the agent can use directly as a config that includes other options from the values file like verbose mode, +custom attributes, FedRAMP and such. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include newrelic.common.naming.truncateToDNSWithSuffix (dict "name" (include "newrelic.common.naming.fullname" .) suffix "agent-config") }} + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "newrelic.common.agentConfig.defaults" . | nindent 4 }} +``` + + + +## _cluster.tpl +### `newrelic.common.cluster` +Returns the cluster name + +Usage: +```mustache +{{ include "newrelic.common.cluster" . }} +``` + + + +## _custom-attributes.tpl +### `newrelic.common.customAttributes` +Return custom attributes in YAML format. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + name: example +data: + custom-attributes.yaml: | + {{- include "newrelic.common.customAttributes" . | nindent 4 }} + custom-attributes.json: | + {{- include "newrelic.common.customAttributes" . | fromYaml | toJson | nindent 4 }} +``` + + + +## _fedramp.tpl +### `newrelic.common.fedramp.enabled` +Returns true if FedRAMP is enabled or an empty string if not. It can be safely used in conditionals as an empty string is a Helm falsiness. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled" . }} +``` + +### `newrelic.common.fedramp.enabled.value` +Returns true if FedRAMP is enabled or false if not. This is to have the value of FedRAMP ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled.value" . }} +``` + + + +## _license.tpl +### `newrelic.common.license.secretName` and ### `newrelic.common.license.secretKeyName` +Returns the secret and key inside the secret where to read the license key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the license key. + +To create the secret use `newrelic.common.license.secret`. + +Usage: +```mustache +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + containers: + - name: agent + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} +``` + + + +## _license_secret.tpl +### `newrelic.common.license.secret` +This function templates the secret that is used by agents and integrations with the license Key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any license key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.license.secret" . -}} +``` + + + +## _insights.tpl +### `newrelic.common.insightsKey.secretName` and ### `newrelic.common.insightsKey.secretKeyName` +Returns the secret and key inside the secret where to read the insights key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the insights key. + +To create the secret use `newrelic.common.insightsKey.secret`. + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: statsd +spec: + containers: + - name: statsd + env: + - name: "INSIGHTS_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + key: {{ include "newrelic.common.insightsKey.secretKeyName" . }} +``` + + + +## _insights_secret.tpl +### `newrelic.common.insightsKey.secret` +This function templates the secret that is used by agents and integrations with the insights key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any insights key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.insightsKey.secret" . -}} +``` + + + +## _low-data-mode.tpl +### `newrelic.common.lowDataMode` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + lowDataMode: # Note that this is empty (nil) +lowDataMode: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `lowdataMode` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.lowDataMode" . }} +``` + + + +## _privileged.tpl +### `newrelic.common.privileged` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + privileged: # Note that this is empty (nil) +privileged: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `privileged` is defined, the global one is going to be always ignored. + +Chart writers could override this and put directly a `true` in the `values.yaml` to override the +default of the common library. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.privileged" . }} +``` + +### `newrelic.common.privileged.value` +Returns true if privileged mode is enabled or false if not. This is to have the value of privileged ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.privileged.value" . }} +``` + + + +## _proxy.tpl +### `newrelic.common.proxy` +Returns the proxy URL configured by the user. + +Usage: +```mustache +{{ include "newrelic.common.proxy" . }} +``` + + + +## _security-context.tpl +Use these functions to share the security context among all charts. Useful in clusters that have security enforcing not to +use the root user (like OpenShift) or users that have an admission webhooks. + +The functions are: +* `newrelic.common.securityContext.container` +* `newrelic.common.securityContext.pod` + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + spec: + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + containers: + - name: example + {{- with include "nriKubernetes.securityContext.container" . }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} +``` + + + +## _staging.tpl +### `newrelic.common.nrStaging` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + nrStaging: # Note that this is empty (nil) +nrStaging: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `nrStaging` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging" . }} +``` + +### `newrelic.common.nrStaging.value` +Returns true if staging is enabled or false if not. This is to have the staging value ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging.value" . }} +``` + + + +## _verbose-log.tpl +### `newrelic.common.verboseLog` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + verboseLog: # Note that this is empty (nil) +verboseLog: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `verboseLog` is defined, the global one is going to be always ignored. + +Usage: +```mustache +{{ include "newrelic.common.verboseLog" . }} +``` + +### `newrelic.common.verboseLog.valueAsBoolean` +Returns true if verbose is enabled or false if not. This is to have the verbose value ready to be templated as a boolean + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsBoolean" . }} +``` + +### `newrelic.common.verboseLog.valueAsInt` +Returns 1 if verbose is enabled or 0 if not. This is to have the verbose value ready to be templated as an integer + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsInt" . }} +``` diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/README.md new file mode 100644 index 000000000..10f08ca67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/README.md @@ -0,0 +1,106 @@ +# Helm Common library + +The common library is a way to unify the UX through all the Helm charts that implement it. + +The tooling suite that New Relic is huge and growing and this allows to set things globally +and locally for a single chart. + +## Documentation for chart writers + +If you are writing a chart that is going to use this library you can check the [developers guide](/library/common-library/DEVELOPERS.md) to see all +the functions/templates that we have implemented, what they do and how to use them. + +## Values managed globally + +We want to have a seamless experience through all the charts so we created this library that tries to standardize the behaviour +of all the charts. Sadly, because of the complexity of all these integrations, not all the charts behave exactly as expected. + +An example is `newrelic-infrastructure` that ignores `hostNetwork` in the control plane scraper because most of the users has the +control plane listening in the node to `localhost`. + +For each chart that has a special behavior (or further information of the behavior) there is a "chart particularities" section +in its README.md that explains which is the expected behavior. + +At the time of writing this, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this +library and honors global options as described in this document. + +Here is a list of global options: + +| Global keys | Local keys | Default | Merged[1](#values-managed-globally-1) | Description | +|-------------|------------|---------|--------------------------------------------------|-------------| +| global.cluster | cluster | `""` | | Name of the Kubernetes cluster monitored | +| global.licenseKey | licenseKey | `""` | | This set this license key to use | +| global.customSecretName | customSecretName | `""` | | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there | +| global.customSecretLicenseKey | customSecretLicenseKey | `""` | | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located | +| global.podLabels | podLabels | `{}` | yes | Additional labels for chart pods | +| global.labels | labels | `{}` | yes | Additional labels for chart objects | +| global.priorityClassName | priorityClassName | `""` | | Sets pod's priorityClassName | +| global.hostNetwork | hostNetwork | `false` | | Sets pod's hostNetwork | +| global.dnsConfig | dnsConfig | `{}` | | Sets pod's dnsConfig | +| global.images.registry | See [Further information](#values-managed-globally-2) | `""` | | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.images.pullSecrets | See [Further information](#values-managed-globally-2) | `[]` | yes | Set secrets to be able to fetch images | +| global.podSecurityContext | podSecurityContext | `{}` | | Sets security context (at pod level) | +| global.containerSecurityContext | containerSecurityContext | `{}` | | Sets security context (at container level) | +| global.affinity | affinity | `{}` | | Sets pod/node affinities | +| global.nodeSelector | nodeSelector | `{}` | | Sets pod's node selector | +| global.tolerations | tolerations | `[]` | | Sets pod's tolerations to node taints | +| global.serviceAccount.create | serviceAccount.create | `true` | | Configures if the service account should be created or not | +| global.serviceAccount.name | serviceAccount.name | name of the release | | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. | +| global.serviceAccount.annotations | serviceAccount.annotations | `{}` | yes | Add these annotations to the service account we create | +| global.customAttributes | customAttributes | `{}` | | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.fedramp | fedramp | `false` | | Enables FedRAMP | +| global.lowDataMode | lowDataMode | `false` | | Reduces number of metrics sent in order to reduce costs | +| global.privileged | privileged | Depends on the chart | | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | +| global.proxy | proxy | `""` | | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.nrStaging | nrStaging | `false` | | Send the metrics to the staging backend. Requires a valid staging license key | +| global.verboseLog | verboseLog | `false` | | Sets the debug/trace logs to this integration or all integrations if it is set globally | + +### Further information + +#### 1. Merged + +Merged means that the values from global are not replaced by the local ones. Think in this example: +```yaml +global: + labels: + global: global + hostNetwork: true + nodeSelector: + global: global + +labels: + local: local +nodeSelector: + local: local +hostNetwork: false +``` + +This values will template `hostNetwork` to `false`, a map of labels `{ "global": "global", "local": "local" }` and a `nodeSelector` with +`{ "local": "local" }`. + +As Helm by default merges all the maps it could be confusing that we have two behaviors (merging `labels` and replacing `nodeSelector`) +the `values` from global to local. This is the rationale behind this: +* `hostNetwork` is templated to `false` because is overriding the value defined globally. +* `labels` are merged because the user may want to label all the New Relic pods at once and label other solution pods differently for + clarity' sake. +* `nodeSelector` does not merge as `labels` because could make it harder to overwrite/delete a selector that comes from global because + of the logic that Helm follows merging maps. + + +#### 2. Fine grain registries + +Some charts only have 1 image while others that can have 2 or more images. The local path for the registry can change depending +on the chart itself. + +As this is mostly unique per helm chart, you should take a look to the chart's values table (or directly to the `values.yaml` file to see all the +images that you can change. + +This should only be needed if you have an advanced setup that forces you to have granularity enough to force a proxy/cache registry per integration. + + + +#### 3. Privileged mode + +By default, from the common library, the privileged mode is set to false. But most of the helm charts require this to be true to fetch more +metrics so could see a true in some charts. The consequences of the privileged mode differ from one chart to another so for each chart that +honors the privileged mode toggle should be a section in the README explaining which is the behavior with it enabled or disabled. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_affinity.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_affinity.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod affinity */ -}} +{{- define "newrelic.common.affinity" -}} + {{- if .Values.affinity -}} + {{- toYaml .Values.affinity -}} + {{- else if .Values.global -}} + {{- if .Values.global.affinity -}} + {{- toYaml .Values.global.affinity -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_agent-config.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..9c32861a0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,26 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +log: + level: trace +{{- end }} + +{{- if (include "newrelic.common.nrStaging" . ) }} +staging: true +{{- end }} + +{{- with include "newrelic.common.proxy" . }} +proxy: {{ . | quote }} +{{- end }} + +{{- with include "newrelic.common.fedramp.enabled" . }} +fedramp: {{ . }} +{{- end }} + +{{- with fromYaml ( include "newrelic.common.customAttributes" . ) }} +custom_attributes: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_cluster.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_cluster.tpl @@ -0,0 +1,15 @@ +{{/* +Return the cluster +*/}} +{{- define "newrelic.common.cluster" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.cluster -}} + {{- .Values.cluster -}} +{{- else if $global.cluster -}} + {{- $global.cluster -}} +{{- else -}} + {{ fail "There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required." }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_custom-attributes.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_custom-attributes.tpl @@ -0,0 +1,17 @@ +{{/* +This will render custom attributes as a YAML ready to be templated or be used with `fromYaml`. +*/}} +{{- define "newrelic.common.customAttributes" -}} +{{- $customAttributes := dict -}} + +{{- $global := index .Values "global" | default dict -}} +{{- if $global.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes $global.customAttributes -}} +{{- end -}} + +{{- if .Values.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes .Values.customAttributes -}} +{{- end -}} + +{{- toYaml $customAttributes -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_dnsconfig.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_dnsconfig.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod dnsConfig */ -}} +{{- define "newrelic.common.dnsConfig" -}} + {{- if .Values.dnsConfig -}} + {{- toYaml .Values.dnsConfig -}} + {{- else if .Values.global -}} + {{- if .Values.global.dnsConfig -}} + {{- toYaml .Values.global.dnsConfig -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_fedramp.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_fedramp.tpl @@ -0,0 +1,25 @@ +{{- /* Defines the fedRAMP flag */ -}} +{{- define "newrelic.common.fedramp.enabled" -}} + {{- if .Values.fedramp -}} + {{- if .Values.fedramp.enabled -}} + {{- .Values.fedramp.enabled -}} + {{- end -}} + {{- else if .Values.global -}} + {{- if .Values.global.fedramp -}} + {{- if .Values.global.fedramp.enabled -}} + {{- .Values.global.fedramp.enabled -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{- /* Return FedRAMP value directly ready to be templated */ -}} +{{- define "newrelic.common.fedramp.enabled.value" -}} +{{- if include "newrelic.common.fedramp.enabled" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_hostnetwork.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_hostnetwork.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the hostNetwork toggle. +This helper allows to override the global `.global.hostNetwork` with the value of `.hostNetwork`. +Returns "true" if `hostNetwork` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.hostNetwork" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- /* +`get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs + +We also want only to return when this is true, returning `false` here will template "false" (string) when doing +an `(include "newrelic.common.hostNetwork" .)`, which is not an "empty string" so it is `true` if it is used +as an evaluation somewhere else. +*/ -}} +{{- if get .Values "hostNetwork" | kindIs "bool" -}} + {{- if .Values.hostNetwork -}} + {{- .Values.hostNetwork -}} + {{- end -}} +{{- else if get $global "hostNetwork" | kindIs "bool" -}} + {{- if $global.hostNetwork -}} + {{- $global.hostNetwork -}} + {{- end -}} +{{- end -}} +{{- end -}} + + +{{- /* +Abstraction of the hostNetwork toggle. +This helper abstracts the function "newrelic.common.hostNetwork" to return true or false directly. +*/ -}} +{{- define "newrelic.common.hostNetwork.value" -}} +{{- if include "newrelic.common.hostNetwork" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_images.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..d4fb43290 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_images.tpl @@ -0,0 +1,94 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "defaultRegistry" .defaultRegistry "context" .context ) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic.common.images.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image registry +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} +{{- $globalRegistry := "" -}} +{{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- with .context.Values.global.images.registry -}} + {{- $globalRegistry = . -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- $localRegistry := "" -}} +{{- if .imageRoot.registry -}} + {{- $localRegistry = .imageRoot.registry -}} +{{- end -}} + +{{- $registry := $localRegistry | default $globalRegistry | default .defaultRegistry -}} +{{- if $registry -}} + {{- $registry -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image repository +{{ include "newrelic.common.images.repository" .Values.path.to.the.image }} +*/ -}} +{{- define "newrelic.common.images.repository" -}} + {{- .repository -}} +{{- end -}} + + + +{{- /* +Return the proper image tag +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.tag" -}} + {{- .imageRoot.tag | default .context.Chart.AppVersion | toString -}} +{{- end -}} + + + +{{- /* +Return the proper Image Pull Registry Secret Names evaluating values as templates +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.path.to.the.images.pullSecrets1, .Values.path.to.the.images.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- if .context.Values.global.images.pullSecrets -}} + {{- range .context.Values.global.images.pullSecrets -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- range .pullSecrets -}} + {{- if not (empty .) -}} + {{- range . -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if $flatlist -}} + {{- toYaml $flatlist -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_insights.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_insights.tpl new file mode 100644 index 000000000..895c37732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_insights.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the Insights Key. +*/}} +{{- define "newrelic.common.insightsKey.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "insightskey" ) -}} +{{- include "newrelic.common.insightsKey._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +*/}} +{{- define "newrelic.common.insightsKey.secretKeyName" -}} +{{- include "newrelic.common.insightsKey._customSecretKey" . | default "insightsKey" -}} +{{- end -}} + +{{/* +Return local insightsKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._licenseKey" -}} +{{- if .Values.insightsKey -}} + {{- .Values.insightsKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.insightsKey -}} + {{- .Values.global.insightsKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the Insights Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretName" -}} +{{- if .Values.customInsightsKeySecretName -}} + {{- .Values.customInsightsKeySecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretName -}} + {{- .Values.global.customInsightsKeySecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretKey" -}} +{{- if .Values.customInsightsKeySecretKey -}} + {{- .Values.customInsightsKeySecretKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretKey }} + {{- .Values.global.customInsightsKeySecretKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_insights_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_insights_secret.yaml.tpl new file mode 100644 index 000000000..556caa6ca --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_insights_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the insights key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.insightsKey.secret" }} +{{- if not (include "newrelic.common.insightsKey._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.insightsKey._licenseKey" .) }} + {{- fail "You must specify a insightsKey or a customInsightsSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.insightsKey.secretKeyName" . }}: {{ include "newrelic.common.insightsKey._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_labels.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_labels.tpl @@ -0,0 +1,54 @@ +{{/* +This will render the labels that should be used in all the manifests used by the helm chart. +*/}} +{{- define "newrelic.common.labels" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- $chart := dict "helm.sh/chart" (include "newrelic.common.naming.chart" . ) -}} +{{- $managedBy := dict "app.kubernetes.io/managed-by" .Release.Service -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $labels := mustMergeOverwrite $chart $managedBy $selectorLabels -}} +{{- if .Chart.AppVersion -}} +{{- $labels = mustMergeOverwrite $labels (dict "app.kubernetes.io/version" .Chart.AppVersion) -}} +{{- end -}} + +{{- $globalUserLabels := $global.labels | default dict -}} +{{- $localUserLabels := .Values.labels | default dict -}} + +{{- $labels = mustMergeOverwrite $labels $globalUserLabels $localUserLabels -}} + +{{- toYaml $labels -}} +{{- end -}} + + + +{{/* +This will render the labels that should be used in deployments/daemonsets template pods as a selector. +*/}} +{{- define "newrelic.common.labels.selectorLabels" -}} +{{- $name := dict "app.kubernetes.io/name" ( include "newrelic.common.naming.name" . ) -}} +{{- $instance := dict "app.kubernetes.io/instance" .Release.Name -}} + +{{- $selectorLabels := mustMergeOverwrite $name $instance -}} + +{{- toYaml $selectorLabels -}} +{{- end }} + + + +{{/* +Pod labels +*/}} +{{- define "newrelic.common.labels.podLabels" -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $global := index .Values "global" | default dict -}} +{{- $globalPodLabels := $global.podLabels | default dict }} + +{{- $localPodLabels := .Values.podLabels | default dict }} + +{{- $podLabels := mustMergeOverwrite $selectorLabels $globalPodLabels $localPodLabels -}} + +{{- toYaml $podLabels -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_license.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..647b4ff43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_license.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "license" ) -}} +{{- include "newrelic.common.license._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +*/}} +{{- define "newrelic.common.license.secretKeyName" -}} +{{- include "newrelic.common.license._customSecretKey" . | default "licenseKey" -}} +{{- end -}} + +{{/* +Return local licenseKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._licenseKey" -}} +{{- if .Values.licenseKey -}} + {{- .Values.licenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.licenseKey -}} + {{- .Values.global.licenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the License Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretName" -}} +{{- if .Values.customSecretName -}} + {{- .Values.customSecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretName -}} + {{- .Values.global.customSecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretKey" -}} +{{- if .Values.customSecretLicenseKey -}} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_license_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_license_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the license key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.license.secret" }} +{{- if not (include "newrelic.common.license._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.license._licenseKey" .) }} + {{- fail "You must specify a licenseKey or a customSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.license.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.license.secretKeyName" . }}: {{ include "newrelic.common.license._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_low-data-mode.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_low-data-mode.tpl @@ -0,0 +1,26 @@ +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..19fa92648 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_naming.tpl @@ -0,0 +1,73 @@ +{{/* +This is an function to be called directly with a string just to truncate strings to +63 chars because some Kubernetes name fields are limited to that. +*/}} +{{- define "newrelic.common.naming.truncateToDNS" -}} +{{- . | trunc 63 | trimSuffix "-" }} +{{- end }} + + + +{{- /* +Given a name and a suffix returns a 'DNS Valid' which always include the suffix, truncating the name if needed. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If suffix is too long it gets truncated but it always takes precedence over name, so a 63 chars suffix would suppress the name. +Usage: +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "" "suffix" "my-suffix" ) }} +*/ -}} +{{- define "newrelic.common.naming.truncateToDNSWithSuffix" -}} +{{- $suffix := (include "newrelic.common.naming.truncateToDNS" .suffix) -}} +{{- $maxLen := (max (sub 63 (add1 (len $suffix))) 0) -}} {{- /* We prepend "-" to the suffix so an additional character is needed */ -}} + +{{- $newName := .name | trunc ($maxLen | int) | trimSuffix "-" -}} +{{- if $newName -}} +{{- printf "%s-%s" $newName $suffix -}} +{{- else -}} +{{ $suffix }} +{{- end -}} + +{{- end -}} + + + +{{/* +Expand the name of the chart. +Uses the Chart name by default if nameOverride is not set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.name" -}} +{{- $name := .Values.nameOverride | default .Chart.Name -}} +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end }} + + + +{{/* +Create a default fully qualified app name. +By default the full name will be "" just in if it has the chart name included in that, if not +it will be concatenated like "-". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.fullname" -}} +{{- $name := include "newrelic.common.naming.name" . -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} + +{{- end -}} + + + +{{/* +Create chart name and version as used by the chart label. +This function should not be used for naming objects. Use "common.naming.{name,fullname}" instead. +*/}} +{{- define "newrelic.common.naming.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_nodeselector.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_nodeselector.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod nodeSelector */ -}} +{{- define "newrelic.common.nodeSelector" -}} + {{- if .Values.nodeSelector -}} + {{- toYaml .Values.nodeSelector -}} + {{- else if .Values.global -}} + {{- if .Values.global.nodeSelector -}} + {{- toYaml .Values.global.nodeSelector -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_priority-class-name.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_priority-class-name.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the pod priorityClassName */ -}} +{{- define "newrelic.common.priorityClassName" -}} + {{- if .Values.priorityClassName -}} + {{- .Values.priorityClassName -}} + {{- else if .Values.global -}} + {{- if .Values.global.priorityClassName -}} + {{- .Values.global.priorityClassName -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_privileged.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_privileged.tpl @@ -0,0 +1,28 @@ +{{- /* +This is a helper that returns whether the chart should assume the user is fine deploying privileged pods. +*/ -}} +{{- define "newrelic.common.privileged" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists. */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values "privileged" | kindIs "bool" -}} + {{- if .Values.privileged -}} + {{- .Values.privileged -}} + {{- end -}} +{{- else if get $global "privileged" | kindIs "bool" -}} + {{- if $global.privileged -}} + {{- $global.privileged -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* Return directly "true" or "false" based in the exist of "newrelic.common.privileged" */ -}} +{{- define "newrelic.common.privileged.value" -}} +{{- if include "newrelic.common.privileged" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_proxy.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_proxy.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the proxy */ -}} +{{- define "newrelic.common.proxy" -}} + {{- if .Values.proxy -}} + {{- .Values.proxy -}} + {{- else if .Values.global -}} + {{- if .Values.global.proxy -}} + {{- .Values.global.proxy -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_security-context.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_security-context.tpl @@ -0,0 +1,23 @@ +{{- /* Defines the container securityContext context */ -}} +{{- define "newrelic.common.securityContext.container" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.containerSecurityContext -}} + {{- toYaml .Values.containerSecurityContext -}} +{{- else if $global.containerSecurityContext -}} + {{- toYaml $global.containerSecurityContext -}} +{{- end -}} +{{- end -}} + + + +{{- /* Defines the pod securityContext context */ -}} +{{- define "newrelic.common.securityContext.pod" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.podSecurityContext -}} + {{- toYaml .Values.podSecurityContext -}} +{{- else if $global.podSecurityContext -}} + {{- toYaml $global.podSecurityContext -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_serviceaccount.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..2d352f6ea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_serviceaccount.tpl @@ -0,0 +1,90 @@ +{{- /* Defines if the service account has to be created or not */ -}} +{{- define "newrelic.common.serviceAccount.create" -}} +{{- $valueFound := false -}} + +{{- /* Look for a global creation of a service account */ -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "create" | kindIs "bool") -}} + {{- $valueFound = true -}} + {{- if .Values.serviceAccount.create -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.serviceAccount.name" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.serviceAccount.create -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Look for a local creation of a service account */ -}} +{{- if not $valueFound -}} + {{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} + {{- $global := index .Values "global" | default dict -}} + {{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "create" | kindIs "bool" -}} + {{- $valueFound = true -}} + {{- if $global.serviceAccount.create -}} + {{- $global.serviceAccount.create -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* In case no serviceAccount value has been found, default to "true" */ -}} +{{- if not $valueFound -}} +true +{{- end -}} +{{- end -}} + + + +{{- /* Defines the name of the service account */ -}} +{{- define "newrelic.common.serviceAccount.name" -}} +{{- $localServiceAccount := "" -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "name" | kindIs "string") -}} + {{- $localServiceAccount = .Values.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := "" -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "name" | kindIs "string" -}} + {{- $globalServiceAccount = $global.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- if (include "newrelic.common.serviceAccount.create" .) -}} + {{- $localServiceAccount | default $globalServiceAccount | default (include "newrelic.common.naming.fullname" .) -}} +{{- else -}} + {{- $localServiceAccount | default $globalServiceAccount | default "default" -}} +{{- end -}} +{{- end -}} + + + +{{- /* Merge the global and local annotations for the service account */ -}} +{{- define "newrelic.common.serviceAccount.annotations" -}} +{{- $localServiceAccount := dict -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if get .Values.serviceAccount "annotations" -}} + {{- $localServiceAccount = .Values.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := dict -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "annotations" -}} + {{- $globalServiceAccount = $global.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $merged := mustMergeOverwrite $globalServiceAccount $localServiceAccount -}} + +{{- if $merged -}} + {{- toYaml $merged -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_staging.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_staging.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the nrStaging toggle. +This helper allows to override the global `.global.nrStaging` with the value of `.nrStaging`. +Returns "true" if `nrStaging` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.nrStaging" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "nrStaging" | kindIs "bool") -}} + {{- if .Values.nrStaging -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.nrStaging" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.nrStaging -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "nrStaging" | kindIs "bool" -}} + {{- if $global.nrStaging -}} + {{- $global.nrStaging -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Returns "true" of "false" directly instead of empty string (Helm falsiness) based on the exit of "newrelic.common.nrStaging" +*/ -}} +{{- define "newrelic.common.nrStaging.value" -}} +{{- if include "newrelic.common.nrStaging" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_tolerations.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_tolerations.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod tolerations */ -}} +{{- define "newrelic.common.tolerations" -}} + {{- if .Values.tolerations -}} + {{- toYaml .Values.tolerations -}} + {{- else if .Values.global -}} + {{- if .Values.global.tolerations -}} + {{- toYaml .Values.global.tolerations -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_verbose-log.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/templates/_verbose-log.tpl @@ -0,0 +1,54 @@ +{{- /* +Abstraction of the verbose toggle. +This helper allows to override the global `.global.verboseLog` with the value of `.verboseLog`. +Returns "true" if `verbose` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.verboseLog" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "verboseLog" | kindIs "bool") -}} + {{- if .Values.verboseLog -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.verboseLog" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.verboseLog -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "verboseLog" | kindIs "bool" -}} + {{- if $global.verboseLog -}} + {{- $global.verboseLog -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return true or false directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsBoolean" -}} +{{- if include "newrelic.common.verboseLog" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return 1 or 0 directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsInt" -}} +{{- if include "newrelic.common.verboseLog" . -}} +1 +{{- else -}} +0 +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/charts/common-library/values.yaml @@ -0,0 +1 @@ +# values are not needed for the library chart, however this file is still needed for helm lint to work. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/ci/test-values.yaml new file mode 100644 index 000000000..6f79dea93 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/ci/test-values.yaml @@ -0,0 +1,5 @@ +cluster: test-cluster + +image: + repository: e2e/metadata-injection + tag: test # Defaults to AppVersion diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/NOTES.txt b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/NOTES.txt new file mode 100644 index 000000000..544124d11 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/NOTES.txt @@ -0,0 +1,23 @@ +Your deployment of the New Relic metadata injection webhook is complete. You can check on the progress of this by running the following command: + + kubectl get deployments -o wide -w --namespace {{ .Release.Namespace }} {{ template "newrelic.common.naming.fullname" . }} + +{{- if .Values.customTLSCertificate }} +You have configure the chart to use a custom tls certificate, make sure to read the 'Manage custom certificates' section of the official docs to find the instructions on how to finish setting up the webhook. + +https://docs.newrelic.com/docs/integrations/kubernetes-integration/link-your-applications/link-your-applications-kubernetes#configure-injection +{{- end }} + +To validate the injection of metadata create a dummy pod containing Busybox by running: + + kubectl create -f https://git.io/vPieo + +Check if New Relic environment variables were injected: + + kubectl exec busybox0 -- env | grep NEW_RELIC_METADATA_KUBERNETES + + NEW_RELIC_METADATA_KUBERNETES_CLUSTER_NAME=fsi + NEW_RELIC_METADATA_KUBERNETES_NODE_NAME=nodea + NEW_RELIC_METADATA_KUBERNETES_NAMESPACE_NAME=default + NEW_RELIC_METADATA_KUBERNETES_POD_NAME=busybox0 + NEW_RELIC_METADATA_KUBERNETES_CONTAINER_NAME=busybox diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/_helpers.tpl new file mode 100644 index 000000000..54a23e981 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/_helpers.tpl @@ -0,0 +1,72 @@ +{{/* vim: set filetype=mustache: */}} + +{{- /* Allow to change pod defaults dynamically */ -}} +{{- define "nri-metadata-injection.securityContext.pod" -}} +{{- if include "newrelic.common.securityContext.pod" . -}} +{{- include "newrelic.common.securityContext.pod" . -}} +{{- else -}} +fsGroup: 1001 +runAsUser: 1001 +runAsGroup: 1001 +{{- end -}} +{{- end -}} + +{{- /* +Naming helpers +*/ -}} + +{{- define "nri-metadata-injection.name.admission" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "admission") }} +{{- end -}} + +{{- define "nri-metadata-injection.fullname.admission" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "admission") }} +{{- end -}} + +{{- define "nri-metadata-injection.fullname.admission.serviceAccount" -}} +{{- if include "newrelic.common.serviceAccount.create" . -}} + {{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "admission") }} +{{- else -}} + {{ include "newrelic.common.serviceAccount.name" . }} +{{- end -}} +{{- end -}} + +{{- define "nri-metadata-injection.name.admission-create" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "admission-create") }} +{{- end -}} + +{{- define "nri-metadata-injection.fullname.admission-create" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "admission-create") }} +{{- end -}} + +{{- define "nri-metadata-injection.name.admission-patch" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "admission-patch") }} +{{- end -}} + +{{- define "nri-metadata-injection.fullname.admission-patch" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "admission-patch") }} +{{- end -}} + +{{- define "nri-metadata-injection.name.self-signed-issuer" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "self-signed-issuer") }} +{{- end -}} + +{{- define "nri-metadata-injection.fullname.self-signed-issuer" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "self-signed-issuer") }} +{{- end -}} + +{{- define "nri-metadata-injection.name.root-issuer" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "root-issuer") }} +{{- end -}} + +{{- define "nri-metadata-injection.fullname.root-issuer" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "root-issuer") }} +{{- end -}} + +{{- define "nri-metadata-injection.name.webhook-cert" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.name" .) "suffix" "webhook-cert") }} +{{- end -}} + +{{- define "nri-metadata-injection.fullname.webhook-cert" -}} +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" (dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "webhook-cert") }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrole.yaml new file mode 100644 index 000000000..275b597c8 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrole.yaml @@ -0,0 +1,27 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "nri-metadata-injection.fullname.admission" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "newrelic.common.naming.name" $ }}-admission + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + verbs: + - get + - update +{{- if .Values.rbac.pspEnabled }} + - apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ include "nri-metadata-injection.fullname.admission" . }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrolebinding.yaml new file mode 100644 index 000000000..cf846745e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "nri-metadata-injection.fullname.admission" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + app: {{ include "nri-metadata-injection.name.admission" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "nri-metadata-injection.fullname.admission" . }} +subjects: + - kind: ServiceAccount + name: {{ include "nri-metadata-injection.fullname.admission.serviceAccount" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-createSecret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-createSecret.yaml new file mode 100644 index 000000000..a04f27935 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-createSecret.yaml @@ -0,0 +1,61 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "nri-metadata-injection.fullname.admission-create" . }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "nri-metadata-injection.name.admission-create" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + template: + metadata: + name: {{ include "nri-metadata-injection.fullname.admission-create" . }} + {{- if .Values.podAnnotations }} + annotations: + {{- toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + labels: + app: {{ include "nri-metadata-injection.name.admission-create" . }} + {{- include "newrelic.common.labels" . | nindent 8 }} + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" ( list .Values.jobImage.pullSecrets ) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 -}} + {{- end }} + containers: + - name: create + image: {{ include "newrelic.common.images.image" ( dict "defaultRegistry" "registry.k8s.io" "imageRoot" .Values.jobImage "context" .) }} + imagePullPolicy: {{ .Values.jobImage.pullPolicy }} + args: + - create + - --host={{ include "newrelic.common.naming.fullname" . }},{{ include "newrelic.common.naming.fullname" . }}.{{ .Release.Namespace }}.svc + - --namespace={{ .Release.Namespace }} + - --secret-name={{ include "nri-metadata-injection.fullname.admission" . }} + - --cert-name=tls.crt + - --key-name=tls.key + {{- if .Values.jobImage.volumeMounts }} + volumeMounts: + {{- .Values.jobImage.volumeMounts | toYaml | nindent 10 }} + {{- end }} + {{- if .Values.jobImage.volumes }} + volumes: + {{- .Values.jobImage.volumes | toYaml | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + serviceAccountName: {{ include "nri-metadata-injection.fullname.admission.serviceAccount" . }} + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- if .Values.tolerations }} + tolerations: + {{- toYaml .Values.tolerations | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-patchWebhook.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-patchWebhook.yaml new file mode 100644 index 000000000..99374ef35 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-patchWebhook.yaml @@ -0,0 +1,61 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "nri-metadata-injection.fullname.admission-patch" . }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "nri-metadata-injection.name.admission-patch" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + template: + metadata: + name: {{ include "nri-metadata-injection.fullname.admission-patch" . }} + {{- if .Values.podAnnotations }} + annotations: + {{- toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + labels: + app: {{ include "nri-metadata-injection.name.admission-patch" . }} + {{- include "newrelic.common.labels" . | nindent 8 }} + spec: + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" ( list .Values.jobImage.pullSecrets ) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 -}} + {{- end }} + containers: + - name: patch + image: {{ include "newrelic.common.images.image" ( dict "defaultRegistry" "registry.k8s.io" "imageRoot" .Values.jobImage "context" .) }} + imagePullPolicy: {{ .Values.jobImage.pullPolicy }} + args: + - patch + - --webhook-name={{ include "newrelic.common.naming.fullname" . }} + - --namespace={{ .Release.Namespace }} + - --secret-name={{ include "nri-metadata-injection.fullname.admission" . }} + - --patch-failure-policy=Ignore + - --patch-validating=false + {{- if .Values.jobImage.volumeMounts }} + volumeMounts: + {{- .Values.jobImage.volumeMounts | toYaml | nindent 10 }} + {{- end }} + {{- if .Values.jobImage.volumes }} + volumes: + {{- .Values.jobImage.volumes | toYaml | nindent 8 }} + {{- end }} + restartPolicy: OnFailure + serviceAccountName: {{ include "nri-metadata-injection.fullname.admission.serviceAccount" . }} + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- if .Values.tolerations }} + tolerations: + {{- toYaml .Values.tolerations | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/psp.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/psp.yaml new file mode 100644 index 000000000..20cf0e3bd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/psp.yaml @@ -0,0 +1,50 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled) (.Values.rbac.pspEnabled)) }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ include "nri-metadata-injection.fullname.admission" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "nri-metadata-injection.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + privileged: false + # Required to prevent escalations to root. + # allowPrivilegeEscalation: false + # This is redundant with non-root + disallow privilege escalation, + # but we can provide it for defense in depth. + #requiredDropCapabilities: + # - ALL + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + - 'persistentVolumeClaim' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + # Permits the container to run with root privileges as well. + rule: 'RunAsAny' + seLinux: + # This policy assumes the nodes are using AppArmor rather than SELinux. + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 0 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/role.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/role.yaml new file mode 100644 index 000000000..e42670257 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/role.yaml @@ -0,0 +1,21 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "nri-metadata-injection.fullname.admission" . }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "nri-metadata-injection.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/rolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/rolebinding.yaml new file mode 100644 index 000000000..e73bf472c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/rolebinding.yaml @@ -0,0 +1,21 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "nri-metadata-injection.fullname.admission" . }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "nri-metadata-injection.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "nri-metadata-injection.fullname.admission" . }} +subjects: + - kind: ServiceAccount + name: {{ include "nri-metadata-injection.fullname.admission.serviceAccount" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/serviceaccount.yaml new file mode 100644 index 000000000..027a59089 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- $createServiceAccount := include "newrelic.common.serviceAccount.create" . -}} +{{- if (and $createServiceAccount (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "nri-metadata-injection.fullname.admission.serviceAccount" . }} + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ include "nri-metadata-injection.name.admission" . }} + {{- include "newrelic.common.labels" . | nindent 4 }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/mutatingWebhookConfiguration.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/mutatingWebhookConfiguration.yaml new file mode 100644 index 000000000..b196d4f59 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/admission-webhooks/mutatingWebhookConfiguration.yaml @@ -0,0 +1,36 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} +{{- if .Values.certManager.enabled }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-root-cert" .Release.Namespace (include "newrelic.common.naming.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-root-cert" .Release.Namespace (include "newrelic.common.naming.fullname" .) | quote }} +{{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +webhooks: +- name: metadata-injection.newrelic.com + clientConfig: + service: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + path: "/mutate" +{{- if not .Values.certManager.enabled }} + caBundle: "" +{{- end }} + rules: + - operations: ["CREATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] +{{- if .Values.injectOnlyLabeledNamespaces }} + scope: Namespaced + namespaceSelector: + matchLabels: + newrelic-metadata-injection: enabled +{{- end }} + failurePolicy: Ignore + timeoutSeconds: {{ .Values.timeoutSeconds }} + sideEffects: None + admissionReviewVersions: ["v1", "v1beta1"] diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/cert-manager.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/cert-manager.yaml new file mode 100644 index 000000000..502fa44bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/cert-manager.yaml @@ -0,0 +1,53 @@ +{{ if .Values.certManager.enabled }} +--- +# Create a selfsigned Issuer, in order to create a root CA certificate for +# signing webhook serving certificates +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "nri-metadata-injection.fullname.self-signed-issuer" . }} + namespace: {{ .Release.Namespace }} +spec: + selfSigned: {} +--- +# Generate a CA Certificate used to sign certificates for the webhook +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "newrelic.common.naming.fullname" . }}-root-cert + namespace: {{ .Release.Namespace }} +spec: + secretName: {{ include "newrelic.common.naming.fullname" . }}-root-cert + duration: {{ .Values.certManager.rootCertificateDuration}} + issuerRef: + name: {{ include "nri-metadata-injection.fullname.self-signed-issuer" . }} + commonName: "ca.webhook.nri" + isCA: true +--- +# Create an Issuer that uses the above generated CA certificate to issue certs +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "nri-metadata-injection.fullname.root-issuer" . }} + namespace: {{ .Release.Namespace }} +spec: + ca: + secretName: {{ include "newrelic.common.naming.fullname" . }}-root-cert +--- + +# Finally, generate a serving certificate for the webhook to use +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "nri-metadata-injection.fullname.webhook-cert" . }} + namespace: {{ .Release.Namespace }} +spec: + secretName: {{ include "nri-metadata-injection.fullname.admission" . }} + duration: {{ .Values.certManager.webhookCertificateDuration }} + issuerRef: + name: {{ include "nri-metadata-injection.fullname.root-issuer" . }} + dnsNames: + - {{ include "newrelic.common.naming.fullname" . }} + - {{ include "newrelic.common.naming.fullname" . }}.{{ .Release.Namespace }} + - {{ include "newrelic.common.naming.fullname" . }}.{{ .Release.Namespace }}.svc +{{ end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/deployment.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/deployment.yaml new file mode 100644 index 000000000..4974dbbc1 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/deployment.yaml @@ -0,0 +1,85 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + {{- /* We cannot use the common library here because of a legacy issue */}} + {{- /* `selector` is immutable and the previous chart did not have all the idiomatic labels */}} + app.kubernetes.io/name: {{ include "newrelic.common.naming.name" . }} + template: + metadata: + {{- if .Values.podAnnotations }} + annotations: + {{- toYaml .Values.podAnnotations | nindent 8 }} + {{- end }} + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} + spec: + {{- with include "nri-metadata-injection.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 -}} + {{- end }} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} + {{- if include "newrelic.common.hostNetwork" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- end }} + + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" ( list .Values.image.pullSecrets ) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 -}} + {{- end }} + containers: + - name: {{ include "newrelic.common.naming.name" . }} + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with include "newrelic.common.securityContext.container" . }} + securityContext: + {{- . | nindent 10 }} + {{- end }} + env: + - name: clusterName + value: {{ include "newrelic.common.cluster" . }} + ports: + - containerPort: 8443 + protocol: TCP + volumeMounts: + - name: tls-key-cert-pair + mountPath: /etc/tls-key-cert-pair + readinessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 1 + periodSeconds: 1 + {{- if .Values.resources }} + resources: + {{ toYaml .Values.resources | nindent 10 }} + {{- end }} + volumes: + - name: tls-key-cert-pair + secret: + secretName: {{ include "nri-metadata-injection.fullname.admission" . }} + nodeSelector: + kubernetes.io/os: linux + {{ include "newrelic.common.nodeSelector" . | nindent 8 }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 -}} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 8 -}} + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/service.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/service.yaml new file mode 100644 index 000000000..e4a57587c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + ports: + - port: 443 + targetPort: 8443 + selector: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 4 }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/cluster_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/cluster_test.yaml new file mode 100644 index 000000000..a28487a06 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/cluster_test.yaml @@ -0,0 +1,39 @@ +suite: test cluster environment variable setup +templates: + - templates/deployment.yaml +release: + name: release + namespace: ns +tests: + - it: clusterName env is properly set + set: + cluster: my-cluster + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: clusterName + value: my-cluster + - it: fail when cluster is not defined + asserts: + - failedTemplate: + errorMessage: There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required. + - it: has a linux node selector by default + set: + cluster: my-cluster + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + - it: has a linux node selector and additional selectors + set: + cluster: my-cluster + nodeSelector: + aCoolTestLabel: aCoolTestValue + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + aCoolTestLabel: aCoolTestValue diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/job_serviceaccount_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/job_serviceaccount_test.yaml new file mode 100644 index 000000000..63b6f0534 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/job_serviceaccount_test.yaml @@ -0,0 +1,59 @@ +suite: test job' serviceAccount +templates: + - templates/admission-webhooks/job-patch/job-createSecret.yaml + - templates/admission-webhooks/job-patch/job-patchWebhook.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: RBAC points to the service account that is created by default + set: + cluster: test-cluster + rbac.create: true + serviceAccount.create: true + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: my-release-nri-metadata-injection-admission + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + cluster: test-cluster + rbac.create: true + serviceAccount.create: false + serviceAccount.name: sa-test + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: sa-test + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + cluster: test-cluster + rbac.create: true + serviceAccount.create: false + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: default + + - it: has a linux node selector by default + set: + cluster: my-cluster + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + + - it: has a linux node selector and additional selectors + set: + cluster: my-cluster + nodeSelector: + aCoolTestLabel: aCoolTestValue + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + aCoolTestLabel: aCoolTestValue diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/rbac_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/rbac_test.yaml new file mode 100644 index 000000000..5a69191df --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/rbac_test.yaml @@ -0,0 +1,38 @@ +suite: test RBAC creation +templates: + - templates/admission-webhooks/job-patch/rolebinding.yaml + - templates/admission-webhooks/job-patch/clusterrolebinding.yaml +release: + name: my-release + namespace: my-namespace +tests: + - it: RBAC points to the service account that is created by default + set: + cluster: test-cluster + rbac.create: true + serviceAccount.create: true + asserts: + - equal: + path: subjects[0].name + value: my-release-nri-metadata-injection-admission + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + cluster: test-cluster + rbac.create: true + serviceAccount.create: false + serviceAccount.name: sa-test + asserts: + - equal: + path: subjects[0].name + value: sa-test + + - it: RBAC points to the service account the user supplies when serviceAccount is disabled + set: + cluster: test-cluster + rbac.create: true + serviceAccount.create: false + asserts: + - equal: + path: subjects[0].name + value: default diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/volume_mounts_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/volume_mounts_test.yaml new file mode 100644 index 000000000..4a3c1327d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/tests/volume_mounts_test.yaml @@ -0,0 +1,30 @@ +suite: check volume mounts is properly set +templates: + - templates/admission-webhooks/job-patch/job-createSecret.yaml + - templates/admission-webhooks/job-patch/job-patchWebhook.yaml +release: + name: release + namespace: ns +tests: + - it: clusterName env is properly set + set: + cluster: my-cluster + jobImage: + volumeMounts: + - name: test-volume + volumePath: /test-volume + volumes: + - name: test-volume-container + emptyDir: {} + + asserts: + - contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: test-volume + volumePath: /test-volume + - contains: + path: spec.template.spec.volumes + content: + name: test-volume-container + emptyDir: {} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/values.yaml new file mode 100644 index 000000000..849135c35 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-metadata-injection/values.yaml @@ -0,0 +1,102 @@ +# -- Override the name of the chart +nameOverride: "" +# -- Override the full name of the release +fullnameOverride: "" + +# -- Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster` +cluster: "" + +# -- Image for the New Relic Metadata Injector +# @default -- See `values.yaml` +image: + registry: + repository: newrelic/k8s-metadata-injection + tag: "" # Defaults to chart's appVersion + pullPolicy: IfNotPresent + # -- The secrets that are needed to pull images from a custom registry. + pullSecrets: [] + # - name: regsecret + +# -- Image for creating the needed certificates of this webhook to work +# @default -- See `values.yaml` +jobImage: + registry: # Defaults to registry.k8s.io + repository: ingress-nginx/kube-webhook-certgen + tag: v1.3.0 + pullPolicy: IfNotPresent + # -- The secrets that are needed to pull images from a custom registry. + pullSecrets: [] + # - name: regsecret + + # -- Volume mounts to add to the job, you might want to mount tmp if Pod Security Policies + # Enforce a read-only root. + volumeMounts: [] + # - name: tmp + # mountPath: /tmp + + # -- Volumes to add to the job container + volumes: [] + # - name: tmp + # emptyDir: {} + +rbac: + # rbac.pspEnabled -- Whether the chart should create Pod Security Policy objects. + pspEnabled: false + +replicas: 1 + +# -- Additional labels for chart objects. Can be configured also with `global.labels` +labels: {} +# -- Annotations to be added to all pods created by the integration. +podAnnotations: {} +# -- Additional labels for chart pods. Can be configured also with `global.podLabels` +podLabels: {} + +# -- Image for creating the needed certificates of this webhook to work +# @default -- 100m/30M -/80M +resources: + limits: + memory: 80M + requests: + cpu: 100m + memory: 30M + +# -- Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` +priorityClassName: "" +# -- (bool) Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` +# @default -- false +hostNetwork: +# -- Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` +dnsConfig: {} +# -- Sets security context (at pod level). Can be configured also with `global.podSecurityContext` +podSecurityContext: {} +# -- Sets security context (at container level). Can be configured also with `global.containerSecurityContext` +containerSecurityContext: {} + +certManager: + # certManager.enabled -- Use cert manager for webhook certs + enabled: false + # -- Sets the root certificate duration. Defaults to 43800h (5 years). + rootCertificateDuration: 43800h + # -- Sets certificate duration. Defaults to 8760h (1 year). + webhookCertificateDuration: 8760h + +# -- Sets pod/node affinities. Can be configured also with `global.affinity` +affinity: {} +# -- Sets pod's node selector. Can be configured also with `global.nodeSelector` +nodeSelector: {} +# -- Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` +tolerations: [] + +# -- Enable the metadata decoration only for pods living in namespaces labeled +# with 'newrelic-metadata-injection=enabled'. +injectOnlyLabeledNamespaces: false + +# -- Use custom tls certificates for the webhook, or let the chart handle it +# automatically. +# Ref: https://docs.newrelic.com/docs/integrations/kubernetes-integration/link-your-applications/link-your-applications-kubernetes#configure-injection +customTLSCertificate: false + +# -- Webhook timeout +# Ref: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts +timeoutSeconds: 28 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/Chart.lock b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/Chart.lock new file mode 100644 index 000000000..13fed1c85 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +digest: sha256:fa87cb007564a39a72739a3e850a91d6b03c0fc27a1115deac042b3ef77b4142 +generated: "2024-07-15T13:04:29.3144+02:00" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/Chart.yaml new file mode 100644 index 000000000..9f4153dab --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/Chart.yaml @@ -0,0 +1,29 @@ +apiVersion: v2 +appVersion: 2.21.4 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.2.0 +description: A Helm chart to deploy the New Relic Prometheus OpenMetrics integration +home: https://docs.newrelic.com/docs/infrastructure/prometheus-integrations/install-configure-openmetrics/configure-prometheus-openmetrics-integrations/ +icon: https://newrelic.com/themes/custom/curio/assets/mediakit/new_relic_logo_vertical.svg +keywords: +- prometheus +- newrelic +- monitoring +maintainers: +- name: alvarocabanas + url: https://github.com/alvarocabanas +- name: sigilioso + url: https://github.com/sigilioso +- name: gsanchezgavier + url: https://github.com/gsanchezgavier +- name: kang-makes + url: https://github.com/kang-makes +- name: paologallinaharbur + url: https://github.com/paologallinaharbur +name: nri-prometheus +sources: +- https://github.com/newrelic/nri-prometheus +- https://github.com/newrelic/nri-prometheus/tree/main/charts/nri-prometheus +version: 2.1.18 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/README.md new file mode 100644 index 000000000..0287b2b2a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/README.md @@ -0,0 +1,116 @@ +# nri-prometheus + +A Helm chart to deploy the New Relic Prometheus OpenMetrics integration + +**Homepage:** + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add nri-prometheus https://newrelic.github.io/nri-prometheus +helm upgrade --install newrelic-prometheus nri-prometheus/nri-prometheus -f your-custom-values.yaml +``` + +## Source Code + +* +* + +## Scraping services and endpoints + +When a service is labeled or annotated with `scrape_enabled_label` (defaults to `prometheus.io/scrape`), +`nri-prometheus` will attempt to hit the service directly, rather than the endpoints behind it. + +This is the default behavior for compatibility reasons, but is known to cause issues if more than one endpoint +is behind the service, as metric queries will be load-balanced as well leading to inaccurate histograms. + +In order to change this behaviour set `scrape_endpoints` to `true` and `scrape_services` to `false`. +This will instruct `nri-prometheus` to scrape the underlying endpoints, as Prometheus server does. + +Existing users that are switching to this behavior should note that, depending on the number of endpoints +behind the services in the cluster the load and the metrics reported by those, data ingestion might see +an increase when flipping this option. Resource requirements might also be impacted, again depending on the number of new targets. + +While it is technically possible to set both `scrape_services` and `scrape_endpoints` to true, we do no recommend +doing so as it will lead to redundant metrics being processed, + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Chart particularities + +### Low data mode +See this snippet from the `values.yaml` file: +```yaml +global: + lowDataMode: false +lowDataMode: false +``` + +To reduce the amount ot metrics we send to New Relic, enabling the `lowDataMode` will add [these transformations](static/lowdatamodedefaults.yaml): +```yaml +transformations: + - description: "Low data mode defaults" + ignore_metrics: + # Ignore the following metrics. + # These metrics are already collected by the New Relic Kubernetes Integration. + - prefixes: + - kube_ + - container_ + - machine_ + - cadvisor_ +``` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Sets pod/node affinities. Can be configured also with `global.affinity` | +| cluster | string | `""` | Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster` | +| config | object | See `values.yaml` | Provides your own `config.yaml` for this integration. Ref: https://docs.newrelic.com/docs/infrastructure/prometheus-integrations/install-configure-openmetrics/configure-prometheus-openmetrics-integrations/#example-configuration-file | +| containerSecurityContext | object | `{}` | Sets security context (at container level). Can be configured also with `global.containerSecurityContext` | +| customSecretLicenseKey | string | `""` | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` | +| customSecretName | string | `""` | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` | +| dnsConfig | object | `{}` | Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` | +| fedramp.enabled | bool | false | Enables FedRAMP. Can be configured also with `global.fedramp.enabled` | +| fullnameOverride | string | `""` | Override the full name of the release | +| hostNetwork | bool | `false` | Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` | +| image | object | See `values.yaml` | Image for the New Relic Kubernetes integration | +| image.pullSecrets | list | `[]` | The secrets that are needed to pull images from a custom registry. | +| labels | object | `{}` | Additional labels for chart objects. Can be configured also with `global.labels` | +| licenseKey | string | `""` | This set this license key to use. Can be configured also with `global.licenseKey` | +| lowDataMode | bool | false | Reduces number of metrics sent in order to reduce costs. Can be configured also with `global.lowDataMode` | +| nameOverride | string | `""` | Override the name of the chart | +| nodeSelector | object | `{}` | Sets pod's node selector. Can be configured also with `global.nodeSelector` | +| nrStaging | bool | false | Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` | +| podAnnotations | object | `{}` | Annotations to be added to all pods created by the integration. | +| podLabels | object | `{}` | Additional labels for chart pods. Can be configured also with `global.podLabels` | +| podSecurityContext | object | `{}` | Sets security context (at pod level). Can be configured also with `global.podSecurityContext` | +| priorityClassName | string | `""` | Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` | +| proxy | string | `""` | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port`. Can be configured also with `global.proxy` | +| rbac.create | bool | `true` | Specifies whether RBAC resources should be created | +| resources | object | `{}` | | +| serviceAccount.annotations | object | `{}` | Add these annotations to the service account we create. Can be configured also with `global.serviceAccount.annotations` | +| serviceAccount.create | bool | `true` | Configures if the service account should be created or not. Can be configured also with `global.serviceAccount.create` | +| serviceAccount.name | string | `nil` | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. Can be configured also with `global.serviceAccount.name` | +| tolerations | list | `[]` | Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` | +| verboseLog | bool | false | Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` | + +## Maintainers + +* [alvarocabanas](https://github.com/alvarocabanas) +* [carlossscastro](https://github.com/carlossscastro) +* [sigilioso](https://github.com/sigilioso) +* [gsanchezgavier](https://github.com/gsanchezgavier) +* [kang-makes](https://github.com/kang-makes) +* [marcsanmi](https://github.com/marcsanmi) +* [paologallinaharbur](https://github.com/paologallinaharbur) +* [roobre](https://github.com/roobre) diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/README.md.gotmpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/README.md.gotmpl new file mode 100644 index 000000000..5c1da4577 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/README.md.gotmpl @@ -0,0 +1,83 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +# Helm installation + +You can install this chart using [`nri-bundle`](https://github.com/newrelic/helm-charts/tree/master/charts/nri-bundle) located in the +[helm-charts repository](https://github.com/newrelic/helm-charts) or directly from this repository by adding this Helm repository: + +```shell +helm repo add nri-prometheus https://newrelic.github.io/nri-prometheus +helm upgrade --install newrelic-prometheus nri-prometheus/nri-prometheus -f your-custom-values.yaml +``` + +{{ template "chart.sourcesSection" . }} + +## Scraping services and endpoints + +When a service is labeled or annotated with `scrape_enabled_label` (defaults to `prometheus.io/scrape`), +`nri-prometheus` will attempt to hit the service directly, rather than the endpoints behind it. + +This is the default behavior for compatibility reasons, but is known to cause issues if more than one endpoint +is behind the service, as metric queries will be load-balanced as well leading to inaccurate histograms. + +In order to change this behaviour set `scrape_endpoints` to `true` and `scrape_services` to `false`. +This will instruct `nri-prometheus` to scrape the underlying endpoints, as Prometheus server does. + +Existing users that are switching to this behavior should note that, depending on the number of endpoints +behind the services in the cluster the load and the metrics reported by those, data ingestion might see +an increase when flipping this option. Resource requirements might also be impacted, again depending on the number of new targets. + +While it is technically possible to set both `scrape_services` and `scrape_endpoints` to true, we do no recommend +doing so as it will lead to redundant metrics being processed, + +## Values managed globally + +This chart implements the [New Relic's common Helm library](https://github.com/newrelic/helm-charts/tree/master/library/common-library) which +means that it honors a wide range of defaults and globals common to most New Relic Helm charts. + +Options that can be defined globally include `affinity`, `nodeSelector`, `tolerations`, `proxy` and others. The full list can be found at +[user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md). + +## Chart particularities + +### Low data mode +See this snippet from the `values.yaml` file: +```yaml +global: + lowDataMode: false +lowDataMode: false +``` + +To reduce the amount ot metrics we send to New Relic, enabling the `lowDataMode` will add [these transformations](static/lowdatamodedefaults.yaml): +```yaml +transformations: + - description: "Low data mode defaults" + ignore_metrics: + # Ignore the following metrics. + # These metrics are already collected by the New Relic Kubernetes Integration. + - prefixes: + - kube_ + - container_ + - machine_ + - cadvisor_ +``` + +{{ template "chart.valuesSection" . }} + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/.helmignore b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/Chart.yaml new file mode 100644 index 000000000..b65ac15d4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: juanjjaramillo + url: https://github.com/juanjjaramillo +- name: csongnr + url: https://github.com/csongnr +- name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR +- name: kang-makes + url: https://github.com/kang-makes +name: common-library +type: library +version: 1.2.0 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/DEVELOPERS.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/DEVELOPERS.md new file mode 100644 index 000000000..3ccc108e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/DEVELOPERS.md @@ -0,0 +1,663 @@ +# Functions/templates documented for chart writers +Here is some rough documentation separated by the file that contains the function, the function +name and how to use it. We are not covering functions that start with `_` (e.g. +`newrelic.common.license._licenseKey`) because they are used internally by this library for +other helpers. Helm does not have the concept of "public" or "private" functions/templates so +this is a convention of ours. + +## _naming.tpl +These functions are used to name objects. + +### `newrelic.common.naming.name` +This is the same as the idiomatic `CHART-NAME.name` that is created when you use `helm create`. + +It honors `.Values.nameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.name" . }} +``` + +### `newrelic.common.naming.fullname` +This is the same as the idiomatic `CHART-NAME.fullname` that is created when you use `helm create` + +It honors `.Values.fullnameOverride`. + +Usage: +```mustache +{{ include "newrelic.common.naming.fullname" . }} +``` + +### `newrelic.common.naming.chart` +This is the same as the idiomatic `CHART-NAME.chart` that is created when you use `helm create`. + +It is mostly useless for chart writers. It is used internally for templating the labels but there +is no reason to keep it "private". + +Usage: +```mustache +{{ include "newrelic.common.naming.chart" . }} +``` + +### `newrelic.common.naming.truncateToDNS` +This is a useful template that could be used to trim a string to 63 chars and does not end with a dash (`-`). +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $truncatedName := include "newrelic.common.naming.truncateToDNS" $nameToTruncate }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-string-that-should-be */ -}} +``` + +### `newrelic.common.naming.truncateToDNSWithSuffix` +This template function is the same as the above but instead of receiving a string you should give a `dict` +with a `name` and a `suffix`. This function will join them with a dash (`-`) and trim the `name` so the +result of `name-suffix` is no more than 63 chars + +Usage: +```mustache +{{ $nameToTruncate := "a-really-really-really-really-REALLY-long-string-that-should-be-truncated-because-it-is-enought-long-to-brak-something" +{{- $suffix := "A-NOT-SO-LONG-SUFFIX" }} +{{- $truncatedName := include "truncateToDNSWithSuffix" (dict "name" $nameToTruncate "suffix" $suffix) }} +{{- $truncatedName }} +{{- /* This should print: a-really-really-really-really-REALLY-long-A-NOT-SO-LONG-SUFFIX */ -}} +``` + + + +## _labels.tpl +### `newrelic.common.labels`, `newrelic.common.labels.selectorLabels` and `newrelic.common.labels.podLabels` +These are functions that are used to label objects. They are configured by this `values.yaml` +```yaml +global: + podLabels: {} # included in all the pods of all the charts that implement this library + labels: {} # included in all the objects of all the charts that implement this library +podLabels: {} # included in all the pods of this chart +labels: {} # included in all the objects of this chart +``` + +label maps are merged from global to local values. + +And chart writer should use them like this: +```mustache +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} +``` + +`newrelic.common.labels.podLabels` includes `newrelic.common.labels.selectorLabels` automatically. + + + +## _priority-class-name.tpl +### `newrelic.common.priorityClassName` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + priorityClassName: "" +priorityClassName: "" +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `priorityClassName` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} +``` + + + +## _hostnetwork.tpl +### `newrelic.common.hostNetwork` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + hostNetwork: # Note that this is empty (nil) +hostNetwork: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `hostNetwork` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.hostNetwork" . }} + hostNetwork: {{ . }} + {{- end }} +``` + +### `newrelic.common.hostNetwork.value` +This function is an abstraction of the function above but this returns directly "true" or "false". + +Be careful with using this with an `if` as Helm does evaluate "false" (string) as `true`. + +Usage (example in a pod spec): +```mustache +spec: + hostNetwork: {{ include "newrelic.common.hostNetwork.value" . }} +``` + + + +## _dnsconfig.tpl +### `newrelic.common.dnsConfig` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + dnsConfig: {} +dnsConfig: {} +``` + +Be careful: chart writers should put an empty string (or any kind of Helm falsiness) for this +library to work properly. If in your values a non-falsy `dnsConfig` is found, the global +one is going to be always ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _images.tpl +These functions help us to deal with how images are templated. This allows setting `registries` +where to fetch images globally while being flexible enough to fit in different maps of images +and deployments with one or more images. This is the example of a complex `values.yaml` that +we are going to use during the documentation of these functions: + +```yaml +global: + images: + registry: nexus-3-instance.internal.clients-domain.tld +jobImage: + registry: # defaults to "example.tld" when empty in these examples + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent + pullSecrets: [] +images: + integration: + registry: + repository: newrelic/nri-kube-events + tag: 1.8.0 + pullPolicy: IfNotPresent + agent: + registry: + repository: newrelic/k8s-events-forwarder + tag: 1.22.0 + pullPolicy: IfNotPresent + pullSecrets: [] +``` + +### `newrelic.common.images.image` +This will return a string with the image ready to be downloaded that includes the registry, the image and the tag. +`defaultRegistry` is used to keep `registry` field empty in `values.yaml` so you can override the image using +`global.images.registry`, your local `jobImage.registry` and be able to fallback to a registry that is not `docker.io` +(Or the default repository that the client could have set in the CRI). + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.image" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.registry` +It returns the registry from the global or local values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For the integration */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.images.agent "context" .) }} +{{- /* For jobImage */}} +{{ include "newrelic.common.images.registry" ( dict "defaultRegistry" "example.tld" "imageRoot" .Values.jobImage "context" .) }} +``` + +### `newrelic.common.images.repository` +It returns the image from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.repository" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.tag` +It returns the image's tag from the values. You should avoid using this helper to create your image +URL and use `newrelic.common.images.image` instead, but it is there to be used in case it is needed. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.jobImage "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.integration "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.images.agent "context" .) }} +``` + +### `newrelic.common.images.renderPullSecrets` +If returns a merged map that contains the pull secrets from the global configuration and the local one. + +Usage: +```mustache +{{- /* For jobImage */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.jobImage.pullSecrets "context" .) }} +{{- /* For the integration */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +{{- /* For the agent */}} +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" .Values.images.pullSecrets "context" .) }} +``` + + + +## _serviceaccount.tpl +These functions are used to evaluate if the service account should be created, with which name and add annotations to it. + +The functions that the common library has implemented for service accounts are: +* `newrelic.common.serviceAccount.create` +* `newrelic.common.serviceAccount.name` +* `newrelic.common.serviceAccount.annotations` + +Usage: +```mustache +{{- if include "newrelic.common.serviceAccount.create" . -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end }} +``` + + + +## _affinity.tpl, _nodeselector.tpl and _tolerations.tpl +These three files are almost the same and they follow the idiomatic way of `helm create`. + +Each function also looks if there is a global value like the other helpers. +```yaml +global: + affinity: {} + nodeSelector: {} + tolerations: [] +affinity: {} +nodeSelector: {} +tolerations: [] +``` + +The values here are replaced instead of be merged. If a value at root level is found, the global one is ignored. + +Usage (example in a pod spec): +```mustache +spec: + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 4 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 4 }} + {{- end }} +``` + + + +## _agent-config.tpl +### `newrelic.common.agentConfig.defaults` +This returns a YAML that the agent can use directly as a config that includes other options from the values file like verbose mode, +custom attributes, FedRAMP and such. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + name: {{ include newrelic.common.naming.truncateToDNSWithSuffix (dict "name" (include "newrelic.common.naming.fullname" .) suffix "agent-config") }} + namespace: {{ .Release.Namespace }} +data: + newrelic-infra.yml: |- + # This is the configuration file for the infrastructure agent. See: + # https://docs.newrelic.com/docs/infrastructure/install-infrastructure-agent/configuration/infrastructure-agent-configuration-settings/ + {{- include "newrelic.common.agentConfig.defaults" . | nindent 4 }} +``` + + + +## _cluster.tpl +### `newrelic.common.cluster` +Returns the cluster name + +Usage: +```mustache +{{ include "newrelic.common.cluster" . }} +``` + + + +## _custom-attributes.tpl +### `newrelic.common.customAttributes` +Return custom attributes in YAML format. + +Usage: +```mustache +apiVersion: v1 +kind: ConfigMap +metadata: + name: example +data: + custom-attributes.yaml: | + {{- include "newrelic.common.customAttributes" . | nindent 4 }} + custom-attributes.json: | + {{- include "newrelic.common.customAttributes" . | fromYaml | toJson | nindent 4 }} +``` + + + +## _fedramp.tpl +### `newrelic.common.fedramp.enabled` +Returns true if FedRAMP is enabled or an empty string if not. It can be safely used in conditionals as an empty string is a Helm falsiness. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled" . }} +``` + +### `newrelic.common.fedramp.enabled.value` +Returns true if FedRAMP is enabled or false if not. This is to have the value of FedRAMP ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.fedramp.enabled.value" . }} +``` + + + +## _license.tpl +### `newrelic.common.license.secretName` and ### `newrelic.common.license.secretKeyName` +Returns the secret and key inside the secret where to read the license key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the license key. + +To create the secret use `newrelic.common.license.secret`. + +Usage: +```mustache +{{- if and (.Values.controlPlane.enabled) (not (include "newrelic.fargate" .)) }} +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + containers: + - name: agent + env: + - name: "NRIA_LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} +``` + + + +## _license_secret.tpl +### `newrelic.common.license.secret` +This function templates the secret that is used by agents and integrations with the license Key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any license key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.license.secret" . -}} +``` + + + +## _insights.tpl +### `newrelic.common.insightsKey.secretName` and ### `newrelic.common.insightsKey.secretKeyName` +Returns the secret and key inside the secret where to read the insights key. + +The common library will take care of using a user-provided custom secret or creating a secret that contains the insights key. + +To create the secret use `newrelic.common.insightsKey.secret`. + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: statsd +spec: + containers: + - name: statsd + env: + - name: "INSIGHTS_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + key: {{ include "newrelic.common.insightsKey.secretKeyName" . }} +``` + + + +## _insights_secret.tpl +### `newrelic.common.insightsKey.secret` +This function templates the secret that is used by agents and integrations with the insights key provided by the user. It will +template nothing (empty string) if the user provides a custom pair of secret name and key. + +This template also fails in case the user has not provided any insights key or custom secret so no safety checks have to be done +by chart writers. + +You just must have a template with these two lines: +```mustache +{{- /* Common library will take care of creating the secret or not. */ -}} +{{- include "newrelic.common.insightsKey.secret" . -}} +``` + + + +## _low-data-mode.tpl +### `newrelic.common.lowDataMode` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + lowDataMode: # Note that this is empty (nil) +lowDataMode: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `lowdataMode` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.lowDataMode" . }} +``` + + + +## _privileged.tpl +### `newrelic.common.privileged` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + privileged: # Note that this is empty (nil) +privileged: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `privileged` is defined, the global one is going to be always ignored. + +Chart writers could override this and put directly a `true` in the `values.yaml` to override the +default of the common library. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.privileged" . }} +``` + +### `newrelic.common.privileged.value` +Returns true if privileged mode is enabled or false if not. This is to have the value of privileged ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.privileged.value" . }} +``` + + + +## _proxy.tpl +### `newrelic.common.proxy` +Returns the proxy URL configured by the user. + +Usage: +```mustache +{{ include "newrelic.common.proxy" . }} +``` + + + +## _security-context.tpl +Use these functions to share the security context among all charts. Useful in clusters that have security enforcing not to +use the root user (like OpenShift) or users that have an admission webhooks. + +The functions are: +* `newrelic.common.securityContext.container` +* `newrelic.common.securityContext.pod` + +Usage: +```mustache +apiVersion: v1 +kind: Pod +metadata: + name: example +spec: + spec: + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + + containers: + - name: example + {{- with include "nriKubernetes.securityContext.container" . }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} +``` + + + +## _staging.tpl +### `newrelic.common.nrStaging` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + nrStaging: # Note that this is empty (nil) +nrStaging: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `nrStaging` is defined, the global one is going to be always ignored. + +This function returns "true" of "" (empty string) so it can be used for evaluating conditionals. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging" . }} +``` + +### `newrelic.common.nrStaging.value` +Returns true if staging is enabled or false if not. This is to have the staging value ready to be templated. + +Usage: +```mustache +{{ include "newrelic.common.nrStaging.value" . }} +``` + + + +## _verbose-log.tpl +### `newrelic.common.verboseLog` +Like almost everything in this library, it reads global and local variables: +```yaml +global: + verboseLog: # Note that this is empty (nil) +verboseLog: # Note that this is empty (nil) +``` + +Be careful: chart writers should NOT PUT ANY VALUE for this library to work properly. If in you +values a `verboseLog` is defined, the global one is going to be always ignored. + +Usage: +```mustache +{{ include "newrelic.common.verboseLog" . }} +``` + +### `newrelic.common.verboseLog.valueAsBoolean` +Returns true if verbose is enabled or false if not. This is to have the verbose value ready to be templated as a boolean + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsBoolean" . }} +``` + +### `newrelic.common.verboseLog.valueAsInt` +Returns 1 if verbose is enabled or 0 if not. This is to have the verbose value ready to be templated as an integer + +Usage: +```mustache +{{ include "newrelic.common.verboseLog.valueAsInt" . }} +``` diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/README.md b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/README.md new file mode 100644 index 000000000..10f08ca67 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/README.md @@ -0,0 +1,106 @@ +# Helm Common library + +The common library is a way to unify the UX through all the Helm charts that implement it. + +The tooling suite that New Relic is huge and growing and this allows to set things globally +and locally for a single chart. + +## Documentation for chart writers + +If you are writing a chart that is going to use this library you can check the [developers guide](/library/common-library/DEVELOPERS.md) to see all +the functions/templates that we have implemented, what they do and how to use them. + +## Values managed globally + +We want to have a seamless experience through all the charts so we created this library that tries to standardize the behaviour +of all the charts. Sadly, because of the complexity of all these integrations, not all the charts behave exactly as expected. + +An example is `newrelic-infrastructure` that ignores `hostNetwork` in the control plane scraper because most of the users has the +control plane listening in the node to `localhost`. + +For each chart that has a special behavior (or further information of the behavior) there is a "chart particularities" section +in its README.md that explains which is the expected behavior. + +At the time of writing this, all the charts from `nri-bundle` except `newrelic-logging` and `synthetics-minion` implements this +library and honors global options as described in this document. + +Here is a list of global options: + +| Global keys | Local keys | Default | Merged[1](#values-managed-globally-1) | Description | +|-------------|------------|---------|--------------------------------------------------|-------------| +| global.cluster | cluster | `""` | | Name of the Kubernetes cluster monitored | +| global.licenseKey | licenseKey | `""` | | This set this license key to use | +| global.customSecretName | customSecretName | `""` | | In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there | +| global.customSecretLicenseKey | customSecretLicenseKey | `""` | | In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located | +| global.podLabels | podLabels | `{}` | yes | Additional labels for chart pods | +| global.labels | labels | `{}` | yes | Additional labels for chart objects | +| global.priorityClassName | priorityClassName | `""` | | Sets pod's priorityClassName | +| global.hostNetwork | hostNetwork | `false` | | Sets pod's hostNetwork | +| global.dnsConfig | dnsConfig | `{}` | | Sets pod's dnsConfig | +| global.images.registry | See [Further information](#values-managed-globally-2) | `""` | | Changes the registry where to get the images. Useful when there is an internal image cache/proxy | +| global.images.pullSecrets | See [Further information](#values-managed-globally-2) | `[]` | yes | Set secrets to be able to fetch images | +| global.podSecurityContext | podSecurityContext | `{}` | | Sets security context (at pod level) | +| global.containerSecurityContext | containerSecurityContext | `{}` | | Sets security context (at container level) | +| global.affinity | affinity | `{}` | | Sets pod/node affinities | +| global.nodeSelector | nodeSelector | `{}` | | Sets pod's node selector | +| global.tolerations | tolerations | `[]` | | Sets pod's tolerations to node taints | +| global.serviceAccount.create | serviceAccount.create | `true` | | Configures if the service account should be created or not | +| global.serviceAccount.name | serviceAccount.name | name of the release | | Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. | +| global.serviceAccount.annotations | serviceAccount.annotations | `{}` | yes | Add these annotations to the service account we create | +| global.customAttributes | customAttributes | `{}` | | Adds extra attributes to the cluster and all the metrics emitted to the backend | +| global.fedramp | fedramp | `false` | | Enables FedRAMP | +| global.lowDataMode | lowDataMode | `false` | | Reduces number of metrics sent in order to reduce costs | +| global.privileged | privileged | Depends on the chart | | In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | +| global.proxy | proxy | `""` | | Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` | +| global.nrStaging | nrStaging | `false` | | Send the metrics to the staging backend. Requires a valid staging license key | +| global.verboseLog | verboseLog | `false` | | Sets the debug/trace logs to this integration or all integrations if it is set globally | + +### Further information + +#### 1. Merged + +Merged means that the values from global are not replaced by the local ones. Think in this example: +```yaml +global: + labels: + global: global + hostNetwork: true + nodeSelector: + global: global + +labels: + local: local +nodeSelector: + local: local +hostNetwork: false +``` + +This values will template `hostNetwork` to `false`, a map of labels `{ "global": "global", "local": "local" }` and a `nodeSelector` with +`{ "local": "local" }`. + +As Helm by default merges all the maps it could be confusing that we have two behaviors (merging `labels` and replacing `nodeSelector`) +the `values` from global to local. This is the rationale behind this: +* `hostNetwork` is templated to `false` because is overriding the value defined globally. +* `labels` are merged because the user may want to label all the New Relic pods at once and label other solution pods differently for + clarity' sake. +* `nodeSelector` does not merge as `labels` because could make it harder to overwrite/delete a selector that comes from global because + of the logic that Helm follows merging maps. + + +#### 2. Fine grain registries + +Some charts only have 1 image while others that can have 2 or more images. The local path for the registry can change depending +on the chart itself. + +As this is mostly unique per helm chart, you should take a look to the chart's values table (or directly to the `values.yaml` file to see all the +images that you can change. + +This should only be needed if you have an advanced setup that forces you to have granularity enough to force a proxy/cache registry per integration. + + + +#### 3. Privileged mode + +By default, from the common library, the privileged mode is set to false. But most of the helm charts require this to be true to fetch more +metrics so could see a true in some charts. The consequences of the privileged mode differ from one chart to another so for each chart that +honors the privileged mode toggle should be a section in the README explaining which is the behavior with it enabled or disabled. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_affinity.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_affinity.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod affinity */ -}} +{{- define "newrelic.common.affinity" -}} + {{- if .Values.affinity -}} + {{- toYaml .Values.affinity -}} + {{- else if .Values.global -}} + {{- if .Values.global.affinity -}} + {{- toYaml .Values.global.affinity -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_agent-config.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..9c32861a0 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,26 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +log: + level: trace +{{- end }} + +{{- if (include "newrelic.common.nrStaging" . ) }} +staging: true +{{- end }} + +{{- with include "newrelic.common.proxy" . }} +proxy: {{ . | quote }} +{{- end }} + +{{- with include "newrelic.common.fedramp.enabled" . }} +fedramp: {{ . }} +{{- end }} + +{{- with fromYaml ( include "newrelic.common.customAttributes" . ) }} +custom_attributes: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_cluster.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_cluster.tpl @@ -0,0 +1,15 @@ +{{/* +Return the cluster +*/}} +{{- define "newrelic.common.cluster" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.cluster -}} + {{- .Values.cluster -}} +{{- else if $global.cluster -}} + {{- $global.cluster -}} +{{- else -}} + {{ fail "There is not cluster name definition set neither in `.global.cluster' nor `.cluster' in your values.yaml. Cluster name is required." }} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_custom-attributes.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_custom-attributes.tpl @@ -0,0 +1,17 @@ +{{/* +This will render custom attributes as a YAML ready to be templated or be used with `fromYaml`. +*/}} +{{- define "newrelic.common.customAttributes" -}} +{{- $customAttributes := dict -}} + +{{- $global := index .Values "global" | default dict -}} +{{- if $global.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes $global.customAttributes -}} +{{- end -}} + +{{- if .Values.customAttributes -}} +{{- $customAttributes = mergeOverwrite $customAttributes .Values.customAttributes -}} +{{- end -}} + +{{- toYaml $customAttributes -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_dnsconfig.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_dnsconfig.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod dnsConfig */ -}} +{{- define "newrelic.common.dnsConfig" -}} + {{- if .Values.dnsConfig -}} + {{- toYaml .Values.dnsConfig -}} + {{- else if .Values.global -}} + {{- if .Values.global.dnsConfig -}} + {{- toYaml .Values.global.dnsConfig -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_fedramp.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_fedramp.tpl @@ -0,0 +1,25 @@ +{{- /* Defines the fedRAMP flag */ -}} +{{- define "newrelic.common.fedramp.enabled" -}} + {{- if .Values.fedramp -}} + {{- if .Values.fedramp.enabled -}} + {{- .Values.fedramp.enabled -}} + {{- end -}} + {{- else if .Values.global -}} + {{- if .Values.global.fedramp -}} + {{- if .Values.global.fedramp.enabled -}} + {{- .Values.global.fedramp.enabled -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + + + +{{- /* Return FedRAMP value directly ready to be templated */ -}} +{{- define "newrelic.common.fedramp.enabled.value" -}} +{{- if include "newrelic.common.fedramp.enabled" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_hostnetwork.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_hostnetwork.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the hostNetwork toggle. +This helper allows to override the global `.global.hostNetwork` with the value of `.hostNetwork`. +Returns "true" if `hostNetwork` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.hostNetwork" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} + +{{- /* +`get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs + +We also want only to return when this is true, returning `false` here will template "false" (string) when doing +an `(include "newrelic.common.hostNetwork" .)`, which is not an "empty string" so it is `true` if it is used +as an evaluation somewhere else. +*/ -}} +{{- if get .Values "hostNetwork" | kindIs "bool" -}} + {{- if .Values.hostNetwork -}} + {{- .Values.hostNetwork -}} + {{- end -}} +{{- else if get $global "hostNetwork" | kindIs "bool" -}} + {{- if $global.hostNetwork -}} + {{- $global.hostNetwork -}} + {{- end -}} +{{- end -}} +{{- end -}} + + +{{- /* +Abstraction of the hostNetwork toggle. +This helper abstracts the function "newrelic.common.hostNetwork" to return true or false directly. +*/ -}} +{{- define "newrelic.common.hostNetwork.value" -}} +{{- if include "newrelic.common.hostNetwork" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_images.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..d4fb43290 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_images.tpl @@ -0,0 +1,94 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "defaultRegistry" .defaultRegistry "context" .context ) -}} + {{- $repositoryName := include "newrelic.common.images.repository" .imageRoot -}} + {{- $tag := include "newrelic.common.images.tag" ( dict "imageRoot" .imageRoot "context" .context) -}} + + {{- if $registryName -}} + {{- printf "%s/%s:%s" $registryName $repositoryName $tag | quote -}} + {{- else -}} + {{- printf "%s:%s" $repositoryName $tag | quote -}} + {{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image registry +{{ include "newrelic.common.images.registry" ( dict "imageRoot" .Values.path.to.the.image "defaultRegistry" "your.private.registry.tld" "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} +{{- $globalRegistry := "" -}} +{{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- with .context.Values.global.images.registry -}} + {{- $globalRegistry = . -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- $localRegistry := "" -}} +{{- if .imageRoot.registry -}} + {{- $localRegistry = .imageRoot.registry -}} +{{- end -}} + +{{- $registry := $localRegistry | default $globalRegistry | default .defaultRegistry -}} +{{- if $registry -}} + {{- $registry -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Return the proper image repository +{{ include "newrelic.common.images.repository" .Values.path.to.the.image }} +*/ -}} +{{- define "newrelic.common.images.repository" -}} + {{- .repository -}} +{{- end -}} + + + +{{- /* +Return the proper image tag +{{ include "newrelic.common.images.tag" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.tag" -}} + {{- .imageRoot.tag | default .context.Chart.AppVersion | toString -}} +{{- end -}} + + + +{{- /* +Return the proper Image Pull Registry Secret Names evaluating values as templates +{{ include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.path.to.the.images.pullSecrets1, .Values.path.to.the.images.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.images -}} + {{- if .context.Values.global.images.pullSecrets -}} + {{- range .context.Values.global.images.pullSecrets -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- range .pullSecrets -}} + {{- if not (empty .) -}} + {{- range . -}} + {{- $flatlist = append $flatlist . -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if $flatlist -}} + {{- toYaml $flatlist -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_insights.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_insights.tpl new file mode 100644 index 000000000..895c37732 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_insights.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the Insights Key. +*/}} +{{- define "newrelic.common.insightsKey.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "insightskey" ) -}} +{{- include "newrelic.common.insightsKey._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +*/}} +{{- define "newrelic.common.insightsKey.secretKeyName" -}} +{{- include "newrelic.common.insightsKey._customSecretKey" . | default "insightsKey" -}} +{{- end -}} + +{{/* +Return local insightsKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._licenseKey" -}} +{{- if .Values.insightsKey -}} + {{- .Values.insightsKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.insightsKey -}} + {{- .Values.global.insightsKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the Insights Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretName" -}} +{{- if .Values.customInsightsKeySecretName -}} + {{- .Values.customInsightsKeySecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretName -}} + {{- .Values.global.customInsightsKeySecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the Insights Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.insightsKey._customSecretKey" -}} +{{- if .Values.customInsightsKeySecretKey -}} + {{- .Values.customInsightsKeySecretKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customInsightsKeySecretKey }} + {{- .Values.global.customInsightsKeySecretKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_insights_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_insights_secret.yaml.tpl new file mode 100644 index 000000000..556caa6ca --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_insights_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the insights key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.insightsKey.secret" }} +{{- if not (include "newrelic.common.insightsKey._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.insightsKey._licenseKey" .) }} + {{- fail "You must specify a insightsKey or a customInsightsSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.insightsKey.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.insightsKey.secretKeyName" . }}: {{ include "newrelic.common.insightsKey._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_labels.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_labels.tpl @@ -0,0 +1,54 @@ +{{/* +This will render the labels that should be used in all the manifests used by the helm chart. +*/}} +{{- define "newrelic.common.labels" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- $chart := dict "helm.sh/chart" (include "newrelic.common.naming.chart" . ) -}} +{{- $managedBy := dict "app.kubernetes.io/managed-by" .Release.Service -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $labels := mustMergeOverwrite $chart $managedBy $selectorLabels -}} +{{- if .Chart.AppVersion -}} +{{- $labels = mustMergeOverwrite $labels (dict "app.kubernetes.io/version" .Chart.AppVersion) -}} +{{- end -}} + +{{- $globalUserLabels := $global.labels | default dict -}} +{{- $localUserLabels := .Values.labels | default dict -}} + +{{- $labels = mustMergeOverwrite $labels $globalUserLabels $localUserLabels -}} + +{{- toYaml $labels -}} +{{- end -}} + + + +{{/* +This will render the labels that should be used in deployments/daemonsets template pods as a selector. +*/}} +{{- define "newrelic.common.labels.selectorLabels" -}} +{{- $name := dict "app.kubernetes.io/name" ( include "newrelic.common.naming.name" . ) -}} +{{- $instance := dict "app.kubernetes.io/instance" .Release.Name -}} + +{{- $selectorLabels := mustMergeOverwrite $name $instance -}} + +{{- toYaml $selectorLabels -}} +{{- end }} + + + +{{/* +Pod labels +*/}} +{{- define "newrelic.common.labels.podLabels" -}} +{{- $selectorLabels := fromYaml (include "newrelic.common.labels.selectorLabels" . ) -}} + +{{- $global := index .Values "global" | default dict -}} +{{- $globalPodLabels := $global.podLabels | default dict }} + +{{- $localPodLabels := .Values.podLabels | default dict }} + +{{- $podLabels := mustMergeOverwrite $selectorLabels $globalPodLabels $localPodLabels -}} + +{{- toYaml $podLabels -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_license.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..647b4ff43 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_license.tpl @@ -0,0 +1,56 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{- $default := include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" (include "newrelic.common.naming.fullname" .) "suffix" "license" ) -}} +{{- include "newrelic.common.license._customSecretName" . | default $default -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +*/}} +{{- define "newrelic.common.license.secretKeyName" -}} +{{- include "newrelic.common.license._customSecretKey" . | default "licenseKey" -}} +{{- end -}} + +{{/* +Return local licenseKey if set, global otherwise. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._licenseKey" -}} +{{- if .Values.licenseKey -}} + {{- .Values.licenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.licenseKey -}} + {{- .Values.global.licenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name of the secret holding the License Key. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretName" -}} +{{- if .Values.customSecretName -}} + {{- .Values.customSecretName -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretName -}} + {{- .Values.global.customSecretName -}} + {{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the name key for the License Key inside the secret. +This helper is for internal use. +*/}} +{{- define "newrelic.common.license._customSecretKey" -}} +{{- if .Values.customSecretLicenseKey -}} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.global -}} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_license_secret.yaml.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_license_secret.yaml.tpl @@ -0,0 +1,21 @@ +{{/* +Renders the license key secret if user has not specified a custom secret. +*/}} +{{- define "newrelic.common.license.secret" }} +{{- if not (include "newrelic.common.license._customSecretName" .) }} +{{- /* Fail if licenseKey is empty and required: */ -}} +{{- if not (include "newrelic.common.license._licenseKey" .) }} + {{- fail "You must specify a licenseKey or a customSecretName containing it" }} +{{- end }} +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "newrelic.common.license.secretName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +data: + {{ include "newrelic.common.license.secretKeyName" . }}: {{ include "newrelic.common.license._licenseKey" . | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_low-data-mode.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_low-data-mode.tpl @@ -0,0 +1,26 @@ +{{- /* +Abstraction of the lowDataMode toggle. +This helper allows to override the global `.global.lowDataMode` with the value of `.lowDataMode`. +Returns "true" if `lowDataMode` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.lowDataMode" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "lowDataMode" | kindIs "bool") -}} + {{- if .Values.lowDataMode -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.lowDataMode" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.lowDataMode -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "lowDataMode" | kindIs "bool" -}} + {{- if $global.lowDataMode -}} + {{- $global.lowDataMode -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_naming.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..19fa92648 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_naming.tpl @@ -0,0 +1,73 @@ +{{/* +This is an function to be called directly with a string just to truncate strings to +63 chars because some Kubernetes name fields are limited to that. +*/}} +{{- define "newrelic.common.naming.truncateToDNS" -}} +{{- . | trunc 63 | trimSuffix "-" }} +{{- end }} + + + +{{- /* +Given a name and a suffix returns a 'DNS Valid' which always include the suffix, truncating the name if needed. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If suffix is too long it gets truncated but it always takes precedence over name, so a 63 chars suffix would suppress the name. +Usage: +{{ include "newrelic.common.naming.truncateToDNSWithSuffix" ( dict "name" "" "suffix" "my-suffix" ) }} +*/ -}} +{{- define "newrelic.common.naming.truncateToDNSWithSuffix" -}} +{{- $suffix := (include "newrelic.common.naming.truncateToDNS" .suffix) -}} +{{- $maxLen := (max (sub 63 (add1 (len $suffix))) 0) -}} {{- /* We prepend "-" to the suffix so an additional character is needed */ -}} + +{{- $newName := .name | trunc ($maxLen | int) | trimSuffix "-" -}} +{{- if $newName -}} +{{- printf "%s-%s" $newName $suffix -}} +{{- else -}} +{{ $suffix }} +{{- end -}} + +{{- end -}} + + + +{{/* +Expand the name of the chart. +Uses the Chart name by default if nameOverride is not set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.name" -}} +{{- $name := .Values.nameOverride | default .Chart.Name -}} +{{- include "newrelic.common.naming.truncateToDNS" $name -}} +{{- end }} + + + +{{/* +Create a default fully qualified app name. +By default the full name will be "" just in if it has the chart name included in that, if not +it will be concatenated like "-". This could change if fullnameOverride or +nameOverride are set. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "newrelic.common.naming.fullname" -}} +{{- $name := include "newrelic.common.naming.name" . -}} + +{{- if .Values.fullnameOverride -}} + {{- $name = .Values.fullnameOverride -}} +{{- else if not (contains $name .Release.Name) -}} + {{- $name = printf "%s-%s" .Release.Name $name -}} +{{- end -}} + +{{- include "newrelic.common.naming.truncateToDNS" $name -}} + +{{- end -}} + + + +{{/* +Create chart name and version as used by the chart label. +This function should not be used for naming objects. Use "common.naming.{name,fullname}" instead. +*/}} +{{- define "newrelic.common.naming.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_nodeselector.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_nodeselector.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod nodeSelector */ -}} +{{- define "newrelic.common.nodeSelector" -}} + {{- if .Values.nodeSelector -}} + {{- toYaml .Values.nodeSelector -}} + {{- else if .Values.global -}} + {{- if .Values.global.nodeSelector -}} + {{- toYaml .Values.global.nodeSelector -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_priority-class-name.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_priority-class-name.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the pod priorityClassName */ -}} +{{- define "newrelic.common.priorityClassName" -}} + {{- if .Values.priorityClassName -}} + {{- .Values.priorityClassName -}} + {{- else if .Values.global -}} + {{- if .Values.global.priorityClassName -}} + {{- .Values.global.priorityClassName -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_privileged.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_privileged.tpl @@ -0,0 +1,28 @@ +{{- /* +This is a helper that returns whether the chart should assume the user is fine deploying privileged pods. +*/ -}} +{{- define "newrelic.common.privileged" -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists. */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if get .Values "privileged" | kindIs "bool" -}} + {{- if .Values.privileged -}} + {{- .Values.privileged -}} + {{- end -}} +{{- else if get $global "privileged" | kindIs "bool" -}} + {{- if $global.privileged -}} + {{- $global.privileged -}} + {{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* Return directly "true" or "false" based in the exist of "newrelic.common.privileged" */ -}} +{{- define "newrelic.common.privileged.value" -}} +{{- if include "newrelic.common.privileged" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_proxy.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_proxy.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the proxy */ -}} +{{- define "newrelic.common.proxy" -}} + {{- if .Values.proxy -}} + {{- .Values.proxy -}} + {{- else if .Values.global -}} + {{- if .Values.global.proxy -}} + {{- .Values.global.proxy -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_security-context.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_security-context.tpl @@ -0,0 +1,23 @@ +{{- /* Defines the container securityContext context */ -}} +{{- define "newrelic.common.securityContext.container" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.containerSecurityContext -}} + {{- toYaml .Values.containerSecurityContext -}} +{{- else if $global.containerSecurityContext -}} + {{- toYaml $global.containerSecurityContext -}} +{{- end -}} +{{- end -}} + + + +{{- /* Defines the pod securityContext context */ -}} +{{- define "newrelic.common.securityContext.pod" -}} +{{- $global := index .Values "global" | default dict -}} + +{{- if .Values.podSecurityContext -}} + {{- toYaml .Values.podSecurityContext -}} +{{- else if $global.podSecurityContext -}} + {{- toYaml $global.podSecurityContext -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_serviceaccount.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..2d352f6ea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_serviceaccount.tpl @@ -0,0 +1,90 @@ +{{- /* Defines if the service account has to be created or not */ -}} +{{- define "newrelic.common.serviceAccount.create" -}} +{{- $valueFound := false -}} + +{{- /* Look for a global creation of a service account */ -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "create" | kindIs "bool") -}} + {{- $valueFound = true -}} + {{- if .Values.serviceAccount.create -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.serviceAccount.name" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.serviceAccount.create -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* Look for a local creation of a service account */ -}} +{{- if not $valueFound -}} + {{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} + {{- $global := index .Values "global" | default dict -}} + {{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "create" | kindIs "bool" -}} + {{- $valueFound = true -}} + {{- if $global.serviceAccount.create -}} + {{- $global.serviceAccount.create -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} + +{{- /* In case no serviceAccount value has been found, default to "true" */ -}} +{{- if not $valueFound -}} +true +{{- end -}} +{{- end -}} + + + +{{- /* Defines the name of the service account */ -}} +{{- define "newrelic.common.serviceAccount.name" -}} +{{- $localServiceAccount := "" -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if (get .Values.serviceAccount "name" | kindIs "string") -}} + {{- $localServiceAccount = .Values.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := "" -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "name" | kindIs "string" -}} + {{- $globalServiceAccount = $global.serviceAccount.name -}} + {{- end -}} +{{- end -}} + +{{- if (include "newrelic.common.serviceAccount.create" .) -}} + {{- $localServiceAccount | default $globalServiceAccount | default (include "newrelic.common.naming.fullname" .) -}} +{{- else -}} + {{- $localServiceAccount | default $globalServiceAccount | default "default" -}} +{{- end -}} +{{- end -}} + + + +{{- /* Merge the global and local annotations for the service account */ -}} +{{- define "newrelic.common.serviceAccount.annotations" -}} +{{- $localServiceAccount := dict -}} +{{- if get .Values "serviceAccount" | kindIs "map" -}} + {{- if get .Values.serviceAccount "annotations" -}} + {{- $localServiceAccount = .Values.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $globalServiceAccount := dict -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "serviceAccount" | kindIs "map" -}} + {{- if get $global.serviceAccount "annotations" -}} + {{- $globalServiceAccount = $global.serviceAccount.annotations -}} + {{- end -}} +{{- end -}} + +{{- $merged := mustMergeOverwrite $globalServiceAccount $localServiceAccount -}} + +{{- if $merged -}} + {{- toYaml $merged -}} +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_staging.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_staging.tpl @@ -0,0 +1,39 @@ +{{- /* +Abstraction of the nrStaging toggle. +This helper allows to override the global `.global.nrStaging` with the value of `.nrStaging`. +Returns "true" if `nrStaging` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.nrStaging" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "nrStaging" | kindIs "bool") -}} + {{- if .Values.nrStaging -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.nrStaging" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.nrStaging -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "nrStaging" | kindIs "bool" -}} + {{- if $global.nrStaging -}} + {{- $global.nrStaging -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Returns "true" of "false" directly instead of empty string (Helm falsiness) based on the exit of "newrelic.common.nrStaging" +*/ -}} +{{- define "newrelic.common.nrStaging.value" -}} +{{- if include "newrelic.common.nrStaging" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_tolerations.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_tolerations.tpl @@ -0,0 +1,10 @@ +{{- /* Defines the Pod tolerations */ -}} +{{- define "newrelic.common.tolerations" -}} + {{- if .Values.tolerations -}} + {{- toYaml .Values.tolerations -}} + {{- else if .Values.global -}} + {{- if .Values.global.tolerations -}} + {{- toYaml .Values.global.tolerations -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_verbose-log.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/templates/_verbose-log.tpl @@ -0,0 +1,54 @@ +{{- /* +Abstraction of the verbose toggle. +This helper allows to override the global `.global.verboseLog` with the value of `.verboseLog`. +Returns "true" if `verbose` is enabled, otherwise "" (empty string) +*/ -}} +{{- define "newrelic.common.verboseLog" -}} +{{- /* `get` will return "" (empty string) if value is not found, and the value otherwise, so we can type-assert with kindIs */ -}} +{{- if (get .Values "verboseLog" | kindIs "bool") -}} + {{- if .Values.verboseLog -}} + {{- /* + We want only to return when this is true, returning `false` here will template "false" (string) when doing + an `(include "newrelic.common.verboseLog" .)`, which is not an "empty string" so it is `true` if it is used + as an evaluation somewhere else. + */ -}} + {{- .Values.verboseLog -}} + {{- end -}} +{{- else -}} +{{- /* This allows us to use `$global` as an empty dict directly in case `Values.global` does not exists */ -}} +{{- $global := index .Values "global" | default dict -}} +{{- if get $global "verboseLog" | kindIs "bool" -}} + {{- if $global.verboseLog -}} + {{- $global.verboseLog -}} + {{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return true or false directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsBoolean" -}} +{{- if include "newrelic.common.verboseLog" . -}} +true +{{- else -}} +false +{{- end -}} +{{- end -}} + + + +{{- /* +Abstraction of the verbose toggle. +This helper abstracts the function "newrelic.common.verboseLog" to return 1 or 0 directly. +*/ -}} +{{- define "newrelic.common.verboseLog.valueAsInt" -}} +{{- if include "newrelic.common.verboseLog" . -}} +1 +{{- else -}} +0 +{{- end -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/charts/common-library/values.yaml @@ -0,0 +1 @@ +# values are not needed for the library chart, however this file is still needed for helm lint to work. diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-lowdatamode-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-lowdatamode-values.yaml new file mode 100644 index 000000000..57b307a2d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-lowdatamode-values.yaml @@ -0,0 +1,9 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + +lowDataMode: true + +image: + repository: e2e/nri-prometheus + tag: "test" # Defaults to chart's appVersion diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-override-global-lowdatamode.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-override-global-lowdatamode.yaml new file mode 100644 index 000000000..7ff1a730f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-override-global-lowdatamode.yaml @@ -0,0 +1,10 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + lowDataMode: true + +lowDataMode: false + +image: + repository: e2e/nri-prometheus + tag: "test" # Defaults to chart's appVersion diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-values.yaml new file mode 100644 index 000000000..fcd07b2d3 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/ci/test-values.yaml @@ -0,0 +1,104 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + +lowDataMode: true + +nameOverride: my-custom-name + +image: + registry: + repository: e2e/nri-prometheus + tag: "test" + imagePullPolicy: IfNotPresent + +resources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + +rbac: + create: true + +serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the name template + name: "" + # Specify any annotations to add to the ServiceAccount + annotations: + foo: bar + +# If you wish to provide your own config.yaml file include it under config: +# the sample config file is included here as an example. +config: + scrape_duration: "60s" + scrape_timeout: "15s" + + scrape_services: false + scrape_endpoints: true + + audit: false + + insecure_skip_verify: false + + scrape_enabled_label: "prometheus.io/scrape" + + require_scrape_enabled_label_for_nodes: true + + transformations: + - description: "Custom transformation Example" + rename_attributes: + - metric_prefix: "foo_" + attributes: + old_label: "newLabel" + ignore_metrics: + - prefixes: + - bar_ + copy_attributes: + - from_metric: "foo_info" + to_metrics: "foo_" + match_by: + - namespace + +podAnnotations: + custom-pod-annotation: test + +podSecurityContext: + runAsUser: 1000 + runAsGroup: 3000 + fsGroup: 2000 + +containerSecurityContext: + runAsUser: 2000 + +tolerations: + - key: "key1" + operator: "Exists" + effect: "NoSchedule" + +nodeSelector: + kubernetes.io/os: linux + +affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + +nrStaging: false + +fedramp: + enabled: true + +proxy: + +verboseLog: true diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/static/lowdatamodedefaults.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/static/lowdatamodedefaults.yaml new file mode 100644 index 000000000..f749e28da --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/static/lowdatamodedefaults.yaml @@ -0,0 +1,10 @@ +transformations: + - description: "Low data mode defaults" + ignore_metrics: + # Ignore the following metrics. + # These metrics are already collected by the New Relic Kubernetes Integration. + - prefixes: + - kube_ + - container_ + - machine_ + - cadvisor_ diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/_helpers.tpl b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/_helpers.tpl new file mode 100644 index 000000000..23c072bd7 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/_helpers.tpl @@ -0,0 +1,15 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Returns mergeTransformations +Helm can't merge maps of different types. Need to manually create a `transformations` section. +*/}} +{{- define "nri-prometheus.mergeTransformations" -}} + {{/* Remove current `transformations` from config. */}} + {{- omit .Values.config "transformations" | toYaml | nindent 4 -}} + {{/* Create new `transformations` yaml section with merged configs from .Values.config.transformations and lowDataMode. */}} + transformations: + {{- .Values.config.transformations | toYaml | nindent 4 -}} + {{ $lowDataDefault := .Files.Get "static/lowdatamodedefaults.yaml" | fromYaml }} + {{- $lowDataDefault.transformations | toYaml | nindent 4 -}} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/clusterrole.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/clusterrole.yaml new file mode 100644 index 000000000..ac4734d31 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/clusterrole.yaml @@ -0,0 +1,23 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +rules: +- apiGroups: [""] + resources: + - "nodes" + - "nodes/metrics" + - "nodes/stats" + - "nodes/proxy" + - "pods" + - "services" + - "endpoints" + verbs: ["get", "list", "watch"] +- nonResourceURLs: + - /metrics + verbs: + - get +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/clusterrolebinding.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..44244653f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "newrelic.common.naming.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/configmap.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/configmap.yaml new file mode 100644 index 000000000..5daeed64a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/configmap.yaml @@ -0,0 +1,21 @@ +kind: ConfigMap +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +apiVersion: v1 +data: + config.yaml: | + cluster_name: {{ include "newrelic.common.cluster" . }} +{{- if .Values.config -}} + {{- if and (.Values.config.transformations) (include "newrelic.common.lowDataMode" .) -}} + {{- include "nri-prometheus.mergeTransformations" . -}} + {{- else if (include "newrelic.common.lowDataMode" .) -}} + {{ $lowDataDefault := .Files.Get "static/lowdatamodedefaults.yaml" | fromYaml }} + {{- mergeOverwrite (deepCopy .Values.config) $lowDataDefault | toYaml | nindent 4 -}} + {{- else }} + {{- .Values.config | toYaml | nindent 4 -}} + {{- end -}} +{{- end -}} + diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/deployment.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/deployment.yaml new file mode 100644 index 000000000..8529b71f4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/deployment.yaml @@ -0,0 +1,98 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "newrelic.common.naming.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} +spec: + replicas: 1 + selector: + matchLabels: + {{- /* We cannot use the common library here because of a legacy issue */}} + {{- /* `selector` is inmutable and the previous chart did not have all the idiomatic labels */}} + app.kubernetes.io/name: {{ include "newrelic.common.naming.name" . }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} + {{- with include "newrelic.common.securityContext.pod" . }} + securityContext: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.images.renderPullSecrets" ( dict "pullSecrets" (list .Values.image.pullSecrets) "context" .) }} + imagePullSecrets: + {{- . | nindent 8 }} + {{- end }} + containers: + - name: nri-prometheus + {{- with include "newrelic.common.securityContext.container" . }} + securityContext: + {{- . | nindent 10 }} + {{- end }} + image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.image "context" .) }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - "--configfile=/etc/nri-prometheus/config.yaml" + ports: + - containerPort: 8080 + volumeMounts: + - name: config-volume + mountPath: /etc/nri-prometheus/ + env: + - name: "LICENSE_KEY" + valueFrom: + secretKeyRef: + name: {{ include "newrelic.common.license.secretName" . }} + key: {{ include "newrelic.common.license.secretKeyName" . }} + {{- if (include "newrelic.common.nrStaging" .) }} + - name: "METRIC_API_URL" + value: "https://staging-metric-api.newrelic.com/metric/v1/infra" + {{- else if (include "newrelic.common.fedramp.enabled" .) }} + - name: "METRIC_API_URL" + value: "https://gov-metric-api.newrelic.com/metric/v1" + {{- end }} + {{- with include "newrelic.common.proxy" . }} + - name: EMITTER_PROXY + value: {{ . | quote }} + {{- end }} + {{- with include "newrelic.common.verboseLog" . }} + - name: "VERBOSE" + value: {{ . | quote }} + {{- end }} + - name: "BEARER_TOKEN_FILE" + value: "/var/run/secrets/kubernetes.io/serviceaccount/token" + - name: "CA_FILE" + value: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + resources: + {{- toYaml .Values.resources | nindent 10 }} + volumes: + - name: config-volume + configMap: + name: {{ include "newrelic.common.naming.fullname" . }} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} + {{- end }} + {{- with include "newrelic.common.dnsConfig" . }} + dnsConfig: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.affinity" . }} + affinity: + {{- . | nindent 8 }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/secret.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/secret.yaml new file mode 100644 index 000000000..f558ee86c --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/secret.yaml @@ -0,0 +1,2 @@ +{{- /* Common library will take care of creating the secret or not. */}} +{{- include "newrelic.common.license.secret" . }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/serviceaccount.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/serviceaccount.yaml new file mode 100644 index 000000000..df451ec90 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if (include "newrelic.common.serviceAccount.create" .) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "newrelic.common.serviceAccount.name" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} + {{- with (include "newrelic.common.serviceAccount.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +{{- end -}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/configmap_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/configmap_test.yaml new file mode 100644 index 000000000..ae7d921fe --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/configmap_test.yaml @@ -0,0 +1,86 @@ +suite: test nri-prometheus configmap +templates: + - templates/configmap.yaml + - templates/deployment.yaml +tests: + - it: creates the config map with default config in values.yaml and cluster_name. + set: + licenseKey: fakeLicense + cluster: my-cluster-name + asserts: + - equal: + path: data["config.yaml"] + value: |- + cluster_name: my-cluster-name + audit: false + insecure_skip_verify: false + require_scrape_enabled_label_for_nodes: true + scrape_enabled_label: prometheus.io/scrape + scrape_endpoints: false + scrape_services: true + transformations: [] + template: templates/configmap.yaml + + - it: creates the config map with lowDataMode. + set: + licenseKey: fakeLicense + cluster: my-cluster-name + lowDataMode: true + asserts: + - equal: + path: data["config.yaml"] + value: |- + cluster_name: my-cluster-name + audit: false + insecure_skip_verify: false + require_scrape_enabled_label_for_nodes: true + scrape_enabled_label: prometheus.io/scrape + scrape_endpoints: false + scrape_services: true + transformations: + - description: Low data mode defaults + ignore_metrics: + - prefixes: + - kube_ + - container_ + - machine_ + - cadvisor_ + template: templates/configmap.yaml + + - it: merges existing transformation with lowDataMode. + set: + licenseKey: fakeLicense + cluster: my-cluster-name + lowDataMode: true + config: + transformations: + - description: Custom transformation Example + rename_attributes: + - metric_prefix: test_ + attributes: + container_name: containerName + asserts: + - equal: + path: data["config.yaml"] + value: |- + cluster_name: my-cluster-name + audit: false + insecure_skip_verify: false + require_scrape_enabled_label_for_nodes: true + scrape_enabled_label: prometheus.io/scrape + scrape_endpoints: false + scrape_services: true + transformations: + - description: Custom transformation Example + rename_attributes: + - attributes: + container_name: containerName + metric_prefix: test_ + - description: Low data mode defaults + ignore_metrics: + - prefixes: + - kube_ + - container_ + - machine_ + - cadvisor_ + template: templates/configmap.yaml diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/deployment_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/deployment_test.yaml new file mode 100644 index 000000000..cb6f90340 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/deployment_test.yaml @@ -0,0 +1,82 @@ +suite: test deployment +templates: + - templates/deployment.yaml + - templates/configmap.yaml + +release: + name: release + +tests: + - it: adds defaults. + set: + licenseKey: fakeLicense + cluster: test + asserts: + - equal: + path: spec.template.metadata.labels["app.kubernetes.io/instance"] + value: release + template: templates/deployment.yaml + - equal: + path: spec.template.metadata.labels["app.kubernetes.io/name"] + value: nri-prometheus + template: templates/deployment.yaml + - equal: + path: spec.selector.matchLabels + value: + app.kubernetes.io/name: nri-prometheus + template: templates/deployment.yaml + - isNotEmpty: + path: spec.template.metadata.annotations["checksum/config"] + template: templates/deployment.yaml + + - it: adds METRIC_API_URL when nrStaging is true. + set: + licenseKey: fakeLicense + cluster: test + nrStaging: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: "METRIC_API_URL" + value: "https://staging-metric-api.newrelic.com/metric/v1/infra" + template: templates/deployment.yaml + + - it: adds FedRamp endpoint when FedRamp is enabled. + set: + licenseKey: fakeLicense + cluster: test + fedramp: + enabled: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: "METRIC_API_URL" + value: "https://gov-metric-api.newrelic.com/metric/v1" + template: templates/deployment.yaml + + - it: adds proxy when enabled. + set: + licenseKey: fakeLicense + cluster: test + proxy: "https://my-proxy:9999" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: "EMITTER_PROXY" + value: "https://my-proxy:9999" + template: templates/deployment.yaml + + - it: set priorityClassName. + set: + licenseKey: fakeLicense + cluster: test + priorityClassName: foo + asserts: + - equal: + path: spec.template.spec.priorityClassName + value: foo + template: templates/deployment.yaml + diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/labels_test.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/labels_test.yaml new file mode 100644 index 000000000..2b6cb53bb --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/tests/labels_test.yaml @@ -0,0 +1,32 @@ +suite: test object names +templates: + - templates/clusterrole.yaml + - templates/clusterrolebinding.yaml + - templates/configmap.yaml + - templates/deployment.yaml + - templates/secret.yaml + - templates/serviceaccount.yaml + +release: + name: release + revision: + +tests: + - it: adds default labels. + set: + licenseKey: fakeLicense + cluster: test + asserts: + - equal: + path: metadata.labels["app.kubernetes.io/instance"] + value: release + - equal: + path: metadata.labels["app.kubernetes.io/managed-by"] + value: Helm + - equal: + path: metadata.labels["app.kubernetes.io/name"] + value: nri-prometheus + - isNotEmpty: + path: metadata.labels["app.kubernetes.io/version"] + - isNotEmpty: + path: metadata.labels["helm.sh/chart"] diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/values.yaml new file mode 100644 index 000000000..4c562cc66 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/nri-prometheus/values.yaml @@ -0,0 +1,251 @@ +# -- Override the name of the chart +nameOverride: "" +# -- Override the full name of the release +fullnameOverride: "" + +# -- Name of the Kubernetes cluster monitored. Can be configured also with `global.cluster` +cluster: "" +# -- This set this license key to use. Can be configured also with `global.licenseKey` +licenseKey: "" +# -- In case you don't want to have the license key in you values, this allows you to point to a user created secret to get the key from there. Can be configured also with `global.customSecretName` +customSecretName: "" +# -- In case you don't want to have the license key in you values, this allows you to point to which secret key is the license key located. Can be configured also with `global.customSecretLicenseKey` +customSecretLicenseKey: "" + +# -- Image for the New Relic Kubernetes integration +# @default -- See `values.yaml` +image: + registry: + repository: newrelic/nri-prometheus + tag: "" # Defaults to chart's appVersion + imagePullPolicy: IfNotPresent + # -- The secrets that are needed to pull images from a custom registry. + pullSecrets: [] + # - name: regsecret + +resources: {} + # limits: + # cpu: 200m + # memory: 512Mi + # requests: + # cpu: 100m + # memory: 256Mi + +rbac: + # -- Specifies whether RBAC resources should be created + create: true + +serviceAccount: + # -- Add these annotations to the service account we create. Can be configured also with `global.serviceAccount.annotations` + annotations: {} + # -- Configures if the service account should be created or not. Can be configured also with `global.serviceAccount.create` + create: true + # -- Change the name of the service account. This is honored if you disable on this cahrt the creation of the service account so you can use your own. Can be configured also with `global.serviceAccount.name` + name: + +# -- Annotations to be added to all pods created by the integration. +podAnnotations: {} +# -- Additional labels for chart pods. Can be configured also with `global.podLabels` +podLabels: {} +# -- Additional labels for chart objects. Can be configured also with `global.labels` +labels: {} + +# -- Sets pod's priorityClassName. Can be configured also with `global.priorityClassName` +priorityClassName: "" +# -- (bool) Sets pod's hostNetwork. Can be configured also with `global.hostNetwork` +# @default -- `false` +hostNetwork: +# -- Sets pod's dnsConfig. Can be configured also with `global.dnsConfig` +dnsConfig: {} + +# -- Sets security context (at pod level). Can be configured also with `global.podSecurityContext` +podSecurityContext: {} +# -- Sets security context (at container level). Can be configured also with `global.containerSecurityContext` +containerSecurityContext: {} + +# -- Sets pod/node affinities. Can be configured also with `global.affinity` +affinity: {} +# -- Sets pod's node selector. Can be configured also with `global.nodeSelector` +nodeSelector: {} +# -- Sets pod's tolerations to node taints. Can be configured also with `global.tolerations` +tolerations: [] + + +# -- Provides your own `config.yaml` for this integration. +# Ref: https://docs.newrelic.com/docs/infrastructure/prometheus-integrations/install-configure-openmetrics/configure-prometheus-openmetrics-integrations/#example-configuration-file +# @default -- See `values.yaml` +config: + # How often the integration should run. + # Default: "30s" + # scrape_duration: "30s" + + # The HTTP client timeout when fetching data from targets. + # Default: "5s" + # scrape_timeout: "5s" + + # scrape_services Allows to enable scraping the service and not the endpoints behind. + # When endpoints are scraped this is no longer needed + scrape_services: true + + # scrape_endpoints Allows to enable scraping directly endpoints instead of services as prometheus service natively does. + # Please notice that depending on the number of endpoints behind a service the load can increase considerably + scrape_endpoints: false + + # How old must the entries used for calculating the counters delta be + # before the telemetry emitter expires them. + # Default: "5m" + # telemetry_emitter_delta_expiration_age: "5m" + + # How often must the telemetry emitter check for expired delta entries. + # Default: "5m" + # telemetry_emitter_delta_expiration_check_interval: "5m" + + # Whether the integration should run in audit mode or not. Defaults to false. + # Audit mode logs the uncompressed data sent to New Relic. Use this to log all data sent. + # It does not include verbose mode. This can lead to a high log volume, use with care. + # Default: false + audit: false + + # Whether the integration should skip TLS verification or not. + # Default: false + insecure_skip_verify: false + + # The label used to identify scrapeable targets. + # Targets can be identified using a label or annotation. + # Default: "prometheus.io/scrape" + scrape_enabled_label: "prometheus.io/scrape" + + # Whether k8s nodes need to be labelled to be scraped or not. + # Default: true + require_scrape_enabled_label_for_nodes: true + + # Number of worker threads used for scraping targets. + # For large clusters with many (>400) targets, slowly increase until scrape + # time falls between the desired `scrape_duration`. + # Increasing this value too much will result in huge memory consumption if too + # many metrics are being scraped. + # Default: 4 + # worker_threads: 4 + + # Maximum number of metrics to keep in memory until a report is triggered. + # Changing this value is not recommended unless instructed by the New Relic support team. + # max_stored_metrics: 10000 + + # Minimum amount of time to wait between reports. Cannot be lowered than the default, 200ms. + # Changing this value is not recommended unless instructed by the New Relic support team. + # min_emitter_harvest_period: 200ms + + # targets: + # - description: Secure etcd example + # urls: ["https://192.168.3.1:2379", "https://192.168.3.2:2379", "https://192.168.3.3:2379"] + # If true the Kubernetes Service Account token will be included as a Bearer token in the HTTP request. + # use_bearer: false + # tls_config: + # ca_file_path: "/etc/etcd/etcd-client-ca.crt" + # cert_file_path: "/etc/etcd/etcd-client.crt" + # key_file_path: "/etc/etcd/etcd-client.key" + + # Certificate to add to the root CA that the emitter will use when + # verifying server certificates. + # If left empty, TLS uses the host's root CA set. + # emitter_ca_file: "/path/to/cert/server.pem" + + # Set to true in order to stop autodiscovery in the k8s cluster. It can be useful when running the Pod with a service account + # having limited privileges. + # Default: false + # disable_autodiscovery: false + + # Whether the emitter should skip TLS verification when submitting data. + # Default: false + # emitter_insecure_skip_verify: false + + # Histogram support is based on New Relic's guidelines for higher + # level metrics abstractions https://github.com/newrelic/newrelic-exporter-specs/blob/master/Guidelines.md. + # To better support visualization of this data, percentiles are calculated + # based on the histogram metrics and sent to New Relic. + # By default, the following percentiles are calculated: 50, 95 and 99. + # + # percentiles: + # - 50 + # - 95 + # - 99 + + transformations: [] + # - description: "Custom transformation Example" + # rename_attributes: + # - metric_prefix: "" + # attributes: + # container_name: "containerName" + # pod_name: "podName" + # namespace: "namespaceName" + # node: "nodeName" + # container: "containerName" + # pod: "podName" + # deployment: "deploymentName" + # ignore_metrics: + # # Ignore the following metrics. + # # These metrics are already collected by the New Relic Kubernetes Integration. + # - prefixes: + # - kube_daemonset_ + # - kube_deployment_ + # - kube_endpoint_ + # - kube_namespace_ + # - kube_node_ + # - kube_persistentvolume_ + # - kube_pod_ + # - kube_replicaset_ + # - kube_service_ + # - kube_statefulset_ + # copy_attributes: + # # Copy all the labels from the timeseries with metric name + # # `kube_hpa_labels` into every timeseries with a metric name that + # # starts with `kube_hpa_` only if they share the same `namespace` + # # and `hpa` labels. + # - from_metric: "kube_hpa_labels" + # to_metrics: "kube_hpa_" + # match_by: + # - namespace + # - hpa + # - from_metric: "kube_daemonset_labels" + # to_metrics: "kube_daemonset_" + # match_by: + # - namespace + # - daemonset + # - from_metric: "kube_statefulset_labels" + # to_metrics: "kube_statefulset_" + # match_by: + # - namespace + # - statefulset + # - from_metric: "kube_endpoint_labels" + # to_metrics: "kube_endpoint_" + # match_by: + # - namespace + # - endpoint + # - from_metric: "kube_service_labels" + # to_metrics: "kube_service_" + # match_by: + # - namespace + # - service + # - from_metric: "kube_node_labels" + # to_metrics: "kube_node_" + # match_by: + # - namespace + # - node + +# -- (bool) Reduces number of metrics sent in order to reduce costs. Can be configured also with `global.lowDataMode` +# @default -- false +lowDataMode: + +# -- Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port`. Can be configured also with `global.proxy` +proxy: "" + +# -- (bool) Send the metrics to the staging backend. Requires a valid staging license key. Can be configured also with `global.nrStaging` +# @default -- false +nrStaging: +fedramp: + # fedramp.enabled -- (bool) Enables FedRAMP. Can be configured also with `global.fedramp.enabled` + # @default -- false + enabled: +# -- (bool) Sets the debug logs to this integration or all integrations if it is set globally. Can be configured also with `global.verboseLog` +# @default -- false +verboseLog: diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/Chart.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/Chart.yaml new file mode 100644 index 000000000..a0ce0a388 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/Chart.yaml @@ -0,0 +1,4 @@ +apiVersion: v2 +name: pixie-operator-chart +type: application +version: 0.1.6 diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/crds/olm_crd.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/crds/olm_crd.yaml new file mode 100644 index 000000000..3f5429f78 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/crds/olm_crd.yaml @@ -0,0 +1,9045 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: catalogsources.operators.coreos.com +spec: + group: operators.coreos.com + names: + categories: + - olm + kind: CatalogSource + listKind: CatalogSourceList + plural: catalogsources + shortNames: + - catsrc + singular: catalogsource + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The pretty name of the catalog + jsonPath: .spec.displayName + name: Display + type: string + - description: The type of the catalog + jsonPath: .spec.sourceType + name: Type + type: string + - description: The publisher of the catalog + jsonPath: .spec.publisher + name: Publisher + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: CatalogSource is a repository of CSVs, CRDs, and operator packages. + type: object + required: + - metadata + - spec + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + type: object + required: + - sourceType + properties: + address: + description: 'Address is a host that OLM can use to connect to a pre-existing registry. Format: : Only used when SourceType = SourceTypeGrpc. Ignored when the Image field is set.' + type: string + configMap: + description: ConfigMap is the name of the ConfigMap to be used to back a configmap-server registry. Only used when SourceType = SourceTypeConfigmap or SourceTypeInternal. + type: string + description: + type: string + displayName: + description: Metadata + type: string + grpcPodConfig: + description: GrpcPodConfig exposes different overrides for the pod spec of the CatalogSource Pod. Only used when SourceType = SourceTypeGrpc and Image is set. + type: object + properties: + affinity: + description: Affinity is the catalog source's pod's affinity. + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + extractContent: + description: ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is configured to use *must* be using the file-based catalogs in order to utilize this feature. + type: object + required: + - cacheDir + - catalogDir + properties: + cacheDir: + description: CacheDir is the directory storing the pre-calculated API cache. + type: string + catalogDir: + description: CatalogDir is the directory storing the file-based catalog contents. + type: string + memoryTarget: + description: "MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod will have the following modifications made to the container running the server: - the $GOMEMLIMIT environment variable will be set to this value in bytes - the memory request will be set to this value \n This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if a catalog being served is very large and needs more than the default allocation. If your index image has a file- system cache, determine a good approximation for this value by doubling the size of the package cache at /tmp/cache/cache/packages.json in the index image. \n This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set." + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + nodeSelector: + description: NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node's labels for the pod to be scheduled on that node. + type: object + additionalProperties: + type: string + priorityClassName: + description: If specified, indicates the pod's priority. If not specified, the pod priority will be default or zero if there is no default. + type: string + securityContextConfig: + description: "SecurityContextConfig can be one of `legacy` or `restricted`. The CatalogSource's pod is either injected with the right pod.spec.securityContext and pod.spec.container[*].securityContext values to allow the pod to run in Pod Security Admission (PSA) `restricted` mode, or doesn't set these values at all, in which case the pod can only be run in PSA `baseline` or `privileged` namespaces. Currently if the SecurityContextConfig is unspecified, the default value of `legacy` is used. Specifying a value other than `legacy` or `restricted` result in a validation error. When using older catalog images, which could not be run in `restricted` mode, the SecurityContextConfig should be set to `legacy`. \n In a future version will the default will be set to `restricted`, catalog maintainers should rebuild their catalogs with a version of opm that supports running catalogSource pods in `restricted` mode to prepare for these changes. \n More information about PSA can be found here: https://kubernetes.io/docs/concepts/security/pod-security-admission/'" + type: string + default: legacy + enum: + - legacy + - restricted + tolerations: + description: Tolerations are the catalog source's pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + icon: + type: object + required: + - base64data + - mediatype + properties: + base64data: + type: string + mediatype: + type: string + image: + description: Image is an operator-registry container image to instantiate a registry-server with. Only used when SourceType = SourceTypeGrpc. If present, the address field is ignored. + type: string + priority: + description: 'Priority field assigns a weight to the catalog source to prioritize them so that it can be consumed by the dependency resolver. Usage: Higher weight indicates that this catalog source is preferred over lower weighted catalog sources during dependency resolution. The range of the priority value can go from positive to negative in the range of int32. The default value to a catalog source with unassigned priority would be 0. The catalog source with the same priority values will be ranked lexicographically based on its name.' + type: integer + publisher: + type: string + secrets: + description: Secrets represent set of secrets that can be used to access the contents of the catalog. It is best to keep this list small, since each will need to be tried for every catalog entry. + type: array + items: + type: string + sourceType: + description: SourceType is the type of source + type: string + updateStrategy: + description: UpdateStrategy defines how updated catalog source images can be discovered Consists of an interval that defines polling duration and an embedded strategy type + type: object + properties: + registryPoll: + type: object + properties: + interval: + description: Interval is used to determine the time interval between checks of the latest catalog source version. The catalog operator polls to see if a new version of the catalog source is available. If available, the latest image is pulled and gRPC traffic is directed to the latest catalog source. + type: string + status: + type: object + properties: + conditions: + description: Represents the state of a CatalogSource. Note that Message and Reason represent the original status information, which may be migrated to be conditions based in the future. Any new features introduced will use conditions. + type: array + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + type: object + required: + - lastTransitionTime + - message + - reason + - status + - type + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + type: string + format: date-time + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + type: string + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + type: integer + format: int64 + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. + type: string + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + type: string + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + configMapReference: + type: object + required: + - name + - namespace + properties: + lastUpdateTime: + type: string + format: date-time + name: + type: string + namespace: + type: string + resourceVersion: + type: string + uid: + description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated. + type: string + connectionState: + type: object + required: + - lastObservedState + properties: + address: + type: string + lastConnect: + type: string + format: date-time + lastObservedState: + type: string + latestImageRegistryPoll: + description: The last time the CatalogSource image registry has been polled to ensure the image is up-to-date + type: string + format: date-time + message: + description: A human readable message indicating details about why the CatalogSource is in this condition. + type: string + reason: + description: Reason is the reason the CatalogSource was transitioned to its current state. + type: string + registryService: + type: object + properties: + createdAt: + type: string + format: date-time + port: + type: string + protocol: + type: string + serviceName: + type: string + serviceNamespace: + type: string + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: clusterserviceversions.operators.coreos.com +spec: + group: operators.coreos.com + names: + categories: + - olm + kind: ClusterServiceVersion + listKind: ClusterServiceVersionList + plural: clusterserviceversions + shortNames: + - csv + - csvs + singular: clusterserviceversion + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The name of the CSV + jsonPath: .spec.displayName + name: Display + type: string + - description: The version of the CSV + jsonPath: .spec.version + name: Version + type: string + - description: The name of a CSV that this one replaces + jsonPath: .spec.replaces + name: Replaces + type: string + - jsonPath: .status.phase + name: Phase + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: ClusterServiceVersion is a Custom Resource of type `ClusterServiceVersionSpec`. + type: object + required: + - metadata + - spec + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ClusterServiceVersionSpec declarations tell OLM how to install an operator that can manage apps for a given version. + type: object + required: + - displayName + - install + properties: + annotations: + description: Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. + type: object + additionalProperties: + type: string + apiservicedefinitions: + description: APIServiceDefinitions declares all of the extension apis managed or required by an operator being ran by ClusterServiceVersion. + type: object + properties: + owned: + type: array + items: + description: APIServiceDescription provides details to OLM about apis provided via aggregation + type: object + required: + - group + - kind + - name + - version + properties: + actionDescriptors: + type: array + items: + description: ActionDescriptor describes a declarative action that can be performed on a custom resource instance + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + containerPort: + type: integer + format: int32 + deploymentName: + type: string + description: + type: string + displayName: + type: string + group: + type: string + kind: + type: string + name: + type: string + resources: + type: array + items: + description: APIResourceReference is a reference to a Kubernetes resource type that the referrer utilizes. + type: object + required: + - kind + - name + - version + properties: + kind: + description: Kind of the referenced resource type. + type: string + name: + description: Plural name of the referenced resource type (CustomResourceDefinition.Spec.Names[].Plural). Empty string if the referenced resource type is not a custom resource. + type: string + version: + description: API Version of the referenced resource type. + type: string + specDescriptors: + type: array + items: + description: SpecDescriptor describes a field in a spec block of a CRD so that OLM can consume it + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + statusDescriptors: + type: array + items: + description: StatusDescriptor describes a field in a status block of a CRD so that OLM can consume it + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + version: + type: string + required: + type: array + items: + description: APIServiceDescription provides details to OLM about apis provided via aggregation + type: object + required: + - group + - kind + - name + - version + properties: + actionDescriptors: + type: array + items: + description: ActionDescriptor describes a declarative action that can be performed on a custom resource instance + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + containerPort: + type: integer + format: int32 + deploymentName: + type: string + description: + type: string + displayName: + type: string + group: + type: string + kind: + type: string + name: + type: string + resources: + type: array + items: + description: APIResourceReference is a reference to a Kubernetes resource type that the referrer utilizes. + type: object + required: + - kind + - name + - version + properties: + kind: + description: Kind of the referenced resource type. + type: string + name: + description: Plural name of the referenced resource type (CustomResourceDefinition.Spec.Names[].Plural). Empty string if the referenced resource type is not a custom resource. + type: string + version: + description: API Version of the referenced resource type. + type: string + specDescriptors: + type: array + items: + description: SpecDescriptor describes a field in a spec block of a CRD so that OLM can consume it + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + statusDescriptors: + type: array + items: + description: StatusDescriptor describes a field in a status block of a CRD so that OLM can consume it + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + version: + type: string + cleanup: + description: Cleanup specifies the cleanup behaviour when the CSV gets deleted + type: object + required: + - enabled + properties: + enabled: + type: boolean + customresourcedefinitions: + description: "CustomResourceDefinitions declares all of the CRDs managed or required by an operator being ran by ClusterServiceVersion. \n If the CRD is present in the Owned list, it is implicitly required." + type: object + properties: + owned: + type: array + items: + description: CRDDescription provides details to OLM about the CRDs + type: object + required: + - kind + - name + - version + properties: + actionDescriptors: + type: array + items: + description: ActionDescriptor describes a declarative action that can be performed on a custom resource instance + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + description: + type: string + displayName: + type: string + kind: + type: string + name: + type: string + resources: + type: array + items: + description: APIResourceReference is a reference to a Kubernetes resource type that the referrer utilizes. + type: object + required: + - kind + - name + - version + properties: + kind: + description: Kind of the referenced resource type. + type: string + name: + description: Plural name of the referenced resource type (CustomResourceDefinition.Spec.Names[].Plural). Empty string if the referenced resource type is not a custom resource. + type: string + version: + description: API Version of the referenced resource type. + type: string + specDescriptors: + type: array + items: + description: SpecDescriptor describes a field in a spec block of a CRD so that OLM can consume it + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + statusDescriptors: + type: array + items: + description: StatusDescriptor describes a field in a status block of a CRD so that OLM can consume it + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + version: + type: string + required: + type: array + items: + description: CRDDescription provides details to OLM about the CRDs + type: object + required: + - kind + - name + - version + properties: + actionDescriptors: + type: array + items: + description: ActionDescriptor describes a declarative action that can be performed on a custom resource instance + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + description: + type: string + displayName: + type: string + kind: + type: string + name: + type: string + resources: + type: array + items: + description: APIResourceReference is a reference to a Kubernetes resource type that the referrer utilizes. + type: object + required: + - kind + - name + - version + properties: + kind: + description: Kind of the referenced resource type. + type: string + name: + description: Plural name of the referenced resource type (CustomResourceDefinition.Spec.Names[].Plural). Empty string if the referenced resource type is not a custom resource. + type: string + version: + description: API Version of the referenced resource type. + type: string + specDescriptors: + type: array + items: + description: SpecDescriptor describes a field in a spec block of a CRD so that OLM can consume it + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + statusDescriptors: + type: array + items: + description: StatusDescriptor describes a field in a status block of a CRD so that OLM can consume it + type: object + required: + - path + properties: + description: + type: string + displayName: + type: string + path: + type: string + value: + description: RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding. + type: string + format: byte + x-descriptors: + type: array + items: + type: string + version: + type: string + description: + description: Description of the operator. Can include the features, limitations or use-cases of the operator. + type: string + displayName: + description: The name of the operator in display format. + type: string + icon: + description: The icon for this operator. + type: array + items: + type: object + required: + - base64data + - mediatype + properties: + base64data: + type: string + mediatype: + type: string + install: + description: NamedInstallStrategy represents the block of an ClusterServiceVersion resource where the install strategy is specified. + type: object + required: + - strategy + properties: + spec: + description: StrategyDetailsDeployment represents the parsed details of a Deployment InstallStrategy. + type: object + required: + - deployments + properties: + clusterPermissions: + type: array + items: + description: StrategyDeploymentPermissions describe the rbac rules and service account needed by the install strategy + type: object + required: + - rules + - serviceAccountName + properties: + rules: + type: array + items: + description: PolicyRule holds information that describes a policy rule, but does not contain information about who the rule applies to or which namespace the rule applies to. + type: object + required: + - verbs + properties: + apiGroups: + description: APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups. + type: array + items: + type: string + nonResourceURLs: + description: NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. + type: array + items: + type: string + resourceNames: + description: ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + type: array + items: + type: string + resources: + description: Resources is a list of resources this rule applies to. '*' represents all resources. + type: array + items: + type: string + verbs: + description: Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. '*' represents all verbs. + type: array + items: + type: string + serviceAccountName: + type: string + deployments: + type: array + items: + description: StrategyDeploymentSpec contains the name, spec and labels for the deployment ALM should create + type: object + required: + - name + - spec + properties: + label: + description: Set is a map of label:value. It implements Labels. + type: object + additionalProperties: + type: string + name: + type: string + spec: + description: DeploymentSpec is the specification of the desired behavior of the Deployment. + type: object + required: + - selector + - template + properties: + minReadySeconds: + description: Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready) + type: integer + format: int32 + paused: + description: Indicates that the deployment is paused. + type: boolean + progressDeadlineSeconds: + description: The maximum time in seconds for a deployment to make progress before it is considered to be failed. The deployment controller will continue to process failed deployments and a condition with a ProgressDeadlineExceeded reason will be surfaced in the deployment status. Note that progress will not be estimated during the time a deployment is paused. Defaults to 600s. + type: integer + format: int32 + replicas: + description: Number of desired pods. This is a pointer to distinguish between explicit zero and not specified. Defaults to 1. + type: integer + format: int32 + revisionHistoryLimit: + description: The number of old ReplicaSets to retain to allow rollback. This is a pointer to distinguish between explicit zero and not specified. Defaults to 10. + type: integer + format: int32 + selector: + description: Label selector for pods. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment. It must match the pod template's labels. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + strategy: + description: The deployment strategy to use to replace existing pods with new ones. + type: object + properties: + rollingUpdate: + description: 'Rolling update config params. Present only if DeploymentStrategyType = RollingUpdate. --- TODO: Update this to follow our convention for oneOf, whatever we decide it to be.' + type: object + properties: + maxSurge: + description: 'The maximum number of pods that can be scheduled above the desired number of pods. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). This can not be 0 if MaxUnavailable is 0. Absolute number is calculated from percentage by rounding up. Defaults to 25%. Example: when this is set to 30%, the new ReplicaSet can be scaled up immediately when the rolling update starts, such that the total number of old and new pods do not exceed 130% of desired pods. Once old pods have been killed, new ReplicaSet can be scaled up further, ensuring that total number of pods running at any time during the update is at most 130% of desired pods.' + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + maxUnavailable: + description: 'The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding down. This can not be 0 if MaxSurge is 0. Defaults to 25%. Example: when this is set to 30%, the old ReplicaSet can be scaled down to 70% of desired pods immediately when the rolling update starts. Once new pods are ready, old ReplicaSet can be scaled down further, followed by scaling up the new ReplicaSet, ensuring that the total number of pods available at all times during the update is at least 70% of desired pods.' + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: + description: Type of deployment. Can be "Recreate" or "RollingUpdate". Default is RollingUpdate. + type: string + template: + description: Template describes the pods that will be created. The only allowed template.spec.restartPolicy value is "Always". + type: object + properties: + metadata: + description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + description: 'Specification of the desired behavior of the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' + type: object + required: + - containers + properties: + activeDeadlineSeconds: + description: Optional duration in seconds the pod may be active on the node relative to StartTime before the system will actively try to mark it failed and kill associated containers. Value must be a positive integer. + type: integer + format: int64 + affinity: + description: If specified, the pod's scheduling constraints + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + automountServiceAccountToken: + description: AutomountServiceAccountToken indicates whether a service account token should be automatically mounted. + type: boolean + containers: + description: List of containers belonging to the pod. Containers cannot currently be added or removed. There must be at least one container in a Pod. Cannot be updated. + type: array + items: + description: A single application container that you want to run within a pod. + type: object + required: + - name + properties: + args: + description: 'Arguments to the entrypoint. The container image''s CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container''s environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + type: array + items: + type: string + command: + description: 'Entrypoint array. Not executed within a shell. The container image''s ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container''s environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + type: array + items: + type: string + env: + description: List of environment variables to set in the container. Cannot be updated. + type: array + items: + description: EnvVar represents an environment variable present in a Container. + type: object + required: + - name + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot be used if value is not empty. + type: object + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + type: object + required: + - key + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key must be defined + type: boolean + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.' + type: object + required: + - fieldPath + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.' + type: object + required: + - resource + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + type: object + required: + - key + properties: + key: + description: The key of the secret to select from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + envFrom: + description: List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. + type: array + items: + description: EnvFromSource represents the source of a set of ConfigMaps + type: object + properties: + configMapRef: + description: The ConfigMap to select from + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap must be defined + type: boolean + prefix: + description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should take in response to container lifecycle events. Cannot be updated. + type: object + properties: + postStart: + description: 'PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + tcpSocket: + description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + preStop: + description: 'PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod''s termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod''s termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + tcpSocket: + description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + livenessProbe: + description: 'Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + name: + description: Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default "0.0.0.0" address inside a container will be accessible from the network. Modifying this array with strategic merge patch may corrupt the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. Cannot be updated. + type: array + items: + description: ContainerPort represents a network port in a single container. + type: object + required: + - containerPort + properties: + containerPort: + description: Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536. + type: integer + format: int32 + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: Number of port to expose on the host. If specified, this must be a valid port number, 0 < x < 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this. + type: integer + format: int32 + name: + description: If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services. + type: string + protocol: + description: Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP". + type: string + default: TCP + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + resizePolicy: + description: Resources resize policy for the container. + type: array + items: + description: ContainerResizePolicy represents resource resize policy for the container. + type: object + required: + - resourceName + - restartPolicy + properties: + resourceName: + description: 'Name of the resource to which this resource resize policy applies. Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified resource is resized. If not specified, it defaults to NotRequired. + type: string + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + properties: + claims: + description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable. It can only be set for containers." + type: array + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + type: object + required: + - name + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. + type: string + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + requests: + description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + restartPolicy: + description: 'RestartPolicy defines the restart behavior of individual containers in a pod. This field may only be set for init containers, and the only allowed value is "Always". For non-init containers or when this field is not specified, the restart behavior is defined by the Pod''s restart policy and the container type. Setting the RestartPolicy as "Always" for the init container will have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" will be shut down. This lifecycle differs from normal init containers and is often referred to as a "sidecar" container. Although this init container still starts in the init container sequence, it does not wait for the container to complete before proceeding to the next init container. Instead, the next init container starts immediately after this init container is started, or after any startupProbe has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + type: object + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows. + type: object + properties: + add: + description: Added capabilities + type: array + items: + description: Capability represent POSIX capabilities type + type: string + drop: + description: Removed capabilities + type: array + items: + description: Capability represent POSIX capabilities type + type: string + privileged: + description: Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root filesystem. Default is false. Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: integer + format: int64 + runAsNonRoot: + description: Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: integer + format: int64 + seLinuxOptions: + description: The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: object + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + seccompProfile: + description: The seccomp options to use by this container. If seccomp options are provided at both the pod & container level, the container options override the pod options. Note that this field cannot be set when spec.os.name is windows. + type: object + required: + - type + properties: + localhostProfile: + description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied." + type: string + windowsOptions: + description: The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. + type: object + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should be run as a 'Host Process' container. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + startupProbe: + description: 'StartupProbe indicates that the Pod has successfully initialized. If specified, no other probes are executed until this completes successfully. If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. This can be used to provide different probe parameters at the beginning of a Pod''s lifecycle, when it might take a long time to load data or warm a cache, than during steady-state operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + stdin: + description: Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which the container''s termination message will be written is mounted into the container''s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be used by the container. + type: array + items: + description: volumeDevice describes a mapping of a raw block device within a container. + type: object + required: + - devicePath + - name + properties: + devicePath: + description: devicePath is the path inside of the container that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim in the pod + type: string + volumeMounts: + description: Pod volumes to mount into the container's filesystem. Cannot be updated. + type: array + items: + description: VolumeMount describes a mounting of a Volume within a container. + type: object + required: + - mountPath + - name + properties: + mountPath: + description: Path within the container at which the volume should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. + type: string + workingDir: + description: Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated. + type: string + dnsConfig: + description: Specifies the DNS parameters of a pod. Parameters specified here will be merged to the generated DNS configuration based on DNSPolicy. + type: object + properties: + nameservers: + description: A list of DNS name server IP addresses. This will be appended to the base nameservers generated from DNSPolicy. Duplicated nameservers will be removed. + type: array + items: + type: string + options: + description: A list of DNS resolver options. This will be merged with the base options generated from DNSPolicy. Duplicated entries will be removed. Resolution options given in Options will override those that appear in the base DNSPolicy. + type: array + items: + description: PodDNSConfigOption defines DNS resolver options of a pod. + type: object + properties: + name: + description: Required. + type: string + value: + type: string + searches: + description: A list of DNS search domains for host-name lookup. This will be appended to the base search paths generated from DNSPolicy. Duplicated search paths will be removed. + type: array + items: + type: string + dnsPolicy: + description: Set DNS policy for the pod. Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. + type: string + enableServiceLinks: + description: 'EnableServiceLinks indicates whether information about services should be injected into pod''s environment variables, matching the syntax of Docker links. Optional: Defaults to true.' + type: boolean + ephemeralContainers: + description: List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing pod to perform user-initiated actions such as debugging. This list cannot be specified when creating a pod, and it cannot be modified by updating the pod spec. In order to add an ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. + type: array + items: + description: "An EphemeralContainer is a temporary container that you may add to an existing Pod for user-initiated activities such as debugging. Ephemeral containers have no resource or scheduling guarantees, and they will not be restarted when they exit or when a Pod is removed or restarted. The kubelet may evict a Pod if an ephemeral container causes the Pod to exceed its resource allocation. \n To add an ephemeral container, use the ephemeralcontainers subresource of an existing Pod. Ephemeral containers may not be removed or restarted." + type: object + required: + - name + properties: + args: + description: 'Arguments to the entrypoint. The image''s CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container''s environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + type: array + items: + type: string + command: + description: 'Entrypoint array. Not executed within a shell. The image''s ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container''s environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + type: array + items: + type: string + env: + description: List of environment variables to set in the container. Cannot be updated. + type: array + items: + description: EnvVar represents an environment variable present in a Container. + type: object + required: + - name + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot be used if value is not empty. + type: object + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + type: object + required: + - key + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key must be defined + type: boolean + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.' + type: object + required: + - fieldPath + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.' + type: object + required: + - resource + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + type: object + required: + - key + properties: + key: + description: The key of the secret to select from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + envFrom: + description: List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. + type: array + items: + description: EnvFromSource represents the source of a set of ConfigMaps + type: object + properties: + configMapRef: + description: The ConfigMap to select from + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap must be defined + type: boolean + prefix: + description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Lifecycle is not allowed for ephemeral containers. + type: object + properties: + postStart: + description: 'PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + tcpSocket: + description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + preStop: + description: 'PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod''s termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod''s termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + tcpSocket: + description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + livenessProbe: + description: Probes are not allowed for ephemeral containers. + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + name: + description: Name of the ephemeral container specified as a DNS_LABEL. This name must be unique among all containers, init containers and ephemeral containers. + type: string + ports: + description: Ports are not allowed for ephemeral containers. + type: array + items: + description: ContainerPort represents a network port in a single container. + type: object + required: + - containerPort + properties: + containerPort: + description: Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536. + type: integer + format: int32 + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: Number of port to expose on the host. If specified, this must be a valid port number, 0 < x < 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this. + type: integer + format: int32 + name: + description: If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services. + type: string + protocol: + description: Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP". + type: string + default: TCP + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: Probes are not allowed for ephemeral containers. + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + resizePolicy: + description: Resources resize policy for the container. + type: array + items: + description: ContainerResizePolicy represents resource resize policy for the container. + type: object + required: + - resourceName + - restartPolicy + properties: + resourceName: + description: 'Name of the resource to which this resource resize policy applies. Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified resource is resized. If not specified, it defaults to NotRequired. + type: string + x-kubernetes-list-type: atomic + resources: + description: Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources already allocated to the pod. + type: object + properties: + claims: + description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable. It can only be set for containers." + type: array + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + type: object + required: + - name + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. + type: string + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + requests: + description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + restartPolicy: + description: Restart policy for the container to manage the restart behavior of each container within a pod. This may only be set for init containers. You cannot set this field on ephemeral containers. + type: string + securityContext: + description: 'Optional: SecurityContext defines the security options the ephemeral container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext.' + type: object + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows. + type: object + properties: + add: + description: Added capabilities + type: array + items: + description: Capability represent POSIX capabilities type + type: string + drop: + description: Removed capabilities + type: array + items: + description: Capability represent POSIX capabilities type + type: string + privileged: + description: Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root filesystem. Default is false. Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: integer + format: int64 + runAsNonRoot: + description: Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: integer + format: int64 + seLinuxOptions: + description: The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: object + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + seccompProfile: + description: The seccomp options to use by this container. If seccomp options are provided at both the pod & container level, the container options override the pod options. Note that this field cannot be set when spec.os.name is windows. + type: object + required: + - type + properties: + localhostProfile: + description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied." + type: string + windowsOptions: + description: The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. + type: object + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should be run as a 'Host Process' container. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + startupProbe: + description: Probes are not allowed for ephemeral containers. + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + stdin: + description: Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false + type: boolean + targetContainerName: + description: "If set, the name of the container from PodSpec that this ephemeral container targets. The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. If not set then the ephemeral container uses the namespaces configured in the Pod spec. \n The container runtime must implement support for this feature. If the runtime does not support namespace targeting then the result of setting this field is undefined." + type: string + terminationMessagePath: + description: 'Optional: Path at which the file to which the container''s termination message will be written is mounted into the container''s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be used by the container. + type: array + items: + description: volumeDevice describes a mapping of a raw block device within a container. + type: object + required: + - devicePath + - name + properties: + devicePath: + description: devicePath is the path inside of the container that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim in the pod + type: string + volumeMounts: + description: Pod volumes to mount into the container's filesystem. Subpath mounts are not allowed for ephemeral containers. Cannot be updated. + type: array + items: + description: VolumeMount describes a mounting of a Volume within a container. + type: object + required: + - mountPath + - name + properties: + mountPath: + description: Path within the container at which the volume should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. + type: string + workingDir: + description: Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated. + type: string + hostAliases: + description: HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts file if specified. This is only valid for non-hostNetwork pods. + type: array + items: + description: HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the pod's hosts file. + type: object + properties: + hostnames: + description: Hostnames for the above IP address. + type: array + items: + type: string + ip: + description: IP address of the host file entry. + type: string + hostIPC: + description: 'Use the host''s ipc namespace. Optional: Default to false.' + type: boolean + hostNetwork: + description: Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false. + type: boolean + hostPID: + description: 'Use the host''s pid namespace. Optional: Default to false.' + type: boolean + hostUsers: + description: 'Use the host''s user namespace. Optional: Default to true. If set to true or not present, the pod will be run in the host user namespace, useful for when the pod needs a feature only available to the host user namespace, such as loading a kernel module with CAP_SYS_MODULE. When set to false, a new userns is created for the pod. Setting false is useful for mitigating container breakout vulnerabilities even allowing users to run their containers as root without actually having root privileges on the host. This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature.' + type: boolean + hostname: + description: Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value. + type: string + imagePullSecrets: + description: 'ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod' + type: array + items: + description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + initContainers: + description: 'List of initialization containers belonging to the pod. Init containers are executed in order prior to containers being started. If any init container fails, the pod is considered to have failed and is handled according to its restartPolicy. The name for an init container or normal container must be unique among all containers. Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. The resourceRequirements of an init container are taken into account during scheduling by finding the highest request/limit for each resource type, and then using the max of of that value or the sum of the normal containers. Limits are applied to init containers in a similar fashion. Init containers cannot currently be added or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/' + type: array + items: + description: A single application container that you want to run within a pod. + type: object + required: + - name + properties: + args: + description: 'Arguments to the entrypoint. The container image''s CMD is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container''s environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + type: array + items: + type: string + command: + description: 'Entrypoint array. Not executed within a shell. The container image''s ENTRYPOINT is used if this is not provided. Variable references $(VAR_NAME) are expanded using the container''s environment. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Cannot be updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + type: array + items: + type: string + env: + description: List of environment variables to set in the container. Cannot be updated. + type: array + items: + description: EnvVar represents an environment variable present in a Container. + type: object + required: + - name + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot be used if value is not empty. + type: object + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + type: object + required: + - key + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key must be defined + type: boolean + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.' + type: object + required: + - fieldPath + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.' + type: object + required: + - resource + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + type: object + required: + - key + properties: + key: + description: The key of the secret to select from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + envFrom: + description: List of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Cannot be updated. + type: array + items: + description: EnvFromSource represents the source of a set of ConfigMaps + type: object + properties: + configMapRef: + description: The ConfigMap to select from + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap must be defined + type: boolean + prefix: + description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + image: + description: 'Container image name. More info: https://kubernetes.io/docs/concepts/containers/images This field is optional to allow higher level config management to default or override container images in workload controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system should take in response to container lifecycle events. Cannot be updated. + type: object + properties: + postStart: + description: 'PostStart is called immediately after a container is created. If the handler fails, the container is terminated and restarted according to its restart policy. Other management of the container blocks until the hook completes. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + tcpSocket: + description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + preStop: + description: 'PreStop is called immediately before a container is terminated due to an API request or management event such as liveness/startup probe failure, preemption, resource contention, etc. The handler is not called if the container crashes or exits. The Pod''s termination grace period countdown begins before the PreStop hook is executed. Regardless of the outcome of the handler, the container will eventually terminate within the Pod''s termination grace period (unless delayed by finalizers). Other management of the container blocks until the hook completes or until the termination grace period is reached. More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + tcpSocket: + description: Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept for the backward compatibility. There are no validation of this field and lifecycle hooks will fail in runtime when tcp handler is specified. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + livenessProbe: + description: 'Periodic probe of container liveness. Container will be restarted if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + name: + description: Name of the container specified as a DNS_LABEL. Each container in a pod must have a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the container. Not specifying a port here DOES NOT prevent that port from being exposed. Any port which is listening on the default "0.0.0.0" address inside a container will be accessible from the network. Modifying this array with strategic merge patch may corrupt the data. For more information See https://github.com/kubernetes/kubernetes/issues/108255. Cannot be updated. + type: array + items: + description: ContainerPort represents a network port in a single container. + type: object + required: + - containerPort + properties: + containerPort: + description: Number of port to expose on the pod's IP address. This must be a valid port number, 0 < x < 65536. + type: integer + format: int32 + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: Number of port to expose on the host. If specified, this must be a valid port number, 0 < x < 65536. If HostNetwork is specified, this must match ContainerPort. Most containers do not need this. + type: integer + format: int32 + name: + description: If specified, this must be an IANA_SVC_NAME and unique within the pod. Each named port in a pod must have a unique name. Name for the port that can be referred to by services. + type: string + protocol: + description: Protocol for port. Must be UDP, TCP, or SCTP. Defaults to "TCP". + type: string + default: TCP + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + resizePolicy: + description: Resources resize policy for the container. + type: array + items: + description: ContainerResizePolicy represents resource resize policy for the container. + type: object + required: + - resourceName + - restartPolicy + properties: + resourceName: + description: 'Name of the resource to which this resource resize policy applies. Supported values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when specified resource is resized. If not specified, it defaults to NotRequired. + type: string + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + properties: + claims: + description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable. It can only be set for containers." + type: array + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + type: object + required: + - name + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. + type: string + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + requests: + description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + restartPolicy: + description: 'RestartPolicy defines the restart behavior of individual containers in a pod. This field may only be set for init containers, and the only allowed value is "Always". For non-init containers or when this field is not specified, the restart behavior is defined by the Pod''s restart policy and the container type. Setting the RestartPolicy as "Always" for the init container will have the following effect: this init container will be continually restarted on exit until all regular containers have terminated. Once all regular containers have completed, all init containers with restartPolicy "Always" will be shut down. This lifecycle differs from normal init containers and is often referred to as a "sidecar" container. Although this init container still starts in the init container sequence, it does not wait for the container to complete before proceeding to the next init container. Instead, the next init container starts immediately after this init container is started, or after any startupProbe has successfully completed.' + type: string + securityContext: + description: 'SecurityContext defines the security options the container should be run with. If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + type: object + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls whether a process can gain more privileges than its parent process. This bool directly controls if the no_new_privs flag will be set on the container process. AllowPrivilegeEscalation is true always when the container is: 1) run as Privileged 2) has CAP_SYS_ADMIN Note that this field cannot be set when spec.os.name is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop when running containers. Defaults to the default set of capabilities granted by the container runtime. Note that this field cannot be set when spec.os.name is windows. + type: object + properties: + add: + description: Added capabilities + type: array + items: + description: Capability represent POSIX capabilities type + type: string + drop: + description: Removed capabilities + type: array + items: + description: Capability represent POSIX capabilities type + type: string + privileged: + description: Run container in privileged mode. Processes in privileged containers are essentially equivalent to root on the host. Defaults to false. Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a read-only root filesystem. Default is false. Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: integer + format: int64 + runAsNonRoot: + description: Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: integer + format: int64 + seLinuxOptions: + description: The SELinux context to be applied to the container. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is windows. + type: object + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + seccompProfile: + description: The seccomp options to use by this container. If seccomp options are provided at both the pod & container level, the container options override the pod options. Note that this field cannot be set when spec.os.name is windows. + type: object + required: + - type + properties: + localhostProfile: + description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied." + type: string + windowsOptions: + description: The Windows specific settings applied to all containers. If unspecified, the options from the PodSecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. + type: object + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should be run as a 'Host Process' container. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + startupProbe: + description: 'StartupProbe indicates that the Pod has successfully initialized. If specified, no other probes are executed until this completes successfully. If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. This can be used to provide different probe parameters at the beginning of a Pod''s lifecycle, when it might take a long time to load data or warm a cache, than during steady-state operation. This cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: object + properties: + exec: + description: Exec specifies the action to take. + type: object + properties: + command: + description: Command is the command line to execute inside the container, the working directory for the command is root ('/') in the container's filesystem. The command is simply exec'd, it is not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use a shell, you need to explicitly call out to that shell. Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + type: array + items: + type: string + failureThreshold: + description: Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1. + type: integer + format: int32 + grpc: + description: GRPC specifies an action involving a GRPC port. + type: object + required: + - port + properties: + port: + description: Port number of the gRPC service. Number must be in the range 1 to 65535. + type: integer + format: int32 + service: + description: "Service is the name of the service to place in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). \n If this is not specified, the default behavior is defined by gRPC." + type: string + httpGet: + description: HTTPGet specifies the http request to perform. + type: object + required: + - port + properties: + host: + description: Host name to connect to, defaults to the pod IP. You probably want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP allows repeated headers. + type: array + items: + description: HTTPHeader describes a custom header to be used in HTTP probes + type: object + required: + - name + - value + properties: + name: + description: The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + path: + description: Path to access on the HTTP server. + type: string + port: + description: Name or number of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting to the host. Defaults to HTTP. + type: string + initialDelaySeconds: + description: 'Number of seconds after the container has started before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + periodSeconds: + description: How often (in seconds) to perform the probe. Default to 10 seconds. Minimum value is 1. + type: integer + format: int32 + successThreshold: + description: Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + type: integer + format: int32 + tcpSocket: + description: TCPSocket specifies an action involving a TCP port. + type: object + required: + - port + properties: + host: + description: 'Optional: Host name to connect to, defaults to the pod IP.' + type: string + port: + description: Number or name of the port to access on the container. Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + type: integer + format: int64 + timeoutSeconds: + description: 'Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + type: integer + format: int32 + stdin: + description: Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file to which the container''s termination message will be written is mounted into the container''s filesystem. Message written is intended to be brief final status, such as an assertion failure message. Will be truncated by the node if greater than 4096 bytes. The total message length across all containers will be limited to 12kb. Defaults to /dev/termination-log. Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be used by the container. + type: array + items: + description: volumeDevice describes a mapping of a raw block device within a container. + type: object + required: + - devicePath + - name + properties: + devicePath: + description: devicePath is the path inside of the container that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim in the pod + type: string + volumeMounts: + description: Pod volumes to mount into the container's filesystem. Cannot be updated. + type: array + items: + description: VolumeMount describes a mounting of a Volume within a container. + type: object + required: + - mountPath + - name + properties: + mountPath: + description: Path within the container at which the volume should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. + type: string + workingDir: + description: Container's working directory. If not specified, the container runtime's default will be used, which might be configured in the container image. Cannot be updated. + type: string + nodeName: + description: NodeName is a request to schedule this pod onto a specific node. If it is non-empty, the scheduler simply schedules this pod onto that node, assuming that it fits resource requirements. + type: string + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + x-kubernetes-map-type: atomic + os: + description: "Specifies the OS of the containers in the pod. Some pod and container fields are restricted if this is set. \n If the OS field is set to linux, the following fields must be unset: -securityContext.windowsOptions \n If the OS field is set to windows, following fields must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers - spec.securityContext.seLinuxOptions - spec.securityContext.seccompProfile - spec.securityContext.fsGroup - spec.securityContext.fsGroupChangePolicy - spec.securityContext.sysctls - spec.shareProcessNamespace - spec.securityContext.runAsUser - spec.securityContext.runAsGroup - spec.securityContext.supplementalGroups - spec.containers[*].securityContext.seLinuxOptions - spec.containers[*].securityContext.seccompProfile - spec.containers[*].securityContext.capabilities - spec.containers[*].securityContext.readOnlyRootFilesystem - spec.containers[*].securityContext.privileged - spec.containers[*].securityContext.allowPrivilegeEscalation - spec.containers[*].securityContext.procMount - spec.containers[*].securityContext.runAsUser - spec.containers[*].securityContext.runAsGroup" + type: object + required: + - name + properties: + name: + description: 'Name is the name of the operating system. The currently supported values are linux and windows. Additional value may be defined in future and can be one of: https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration Clients should expect to handle additional values and treat unrecognized values in this field as os: null' + type: string + overhead: + description: 'Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. This field will be autopopulated at admission time by the RuntimeClass admission controller. If the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. The RuntimeClass admission controller will reject Pod create requests which have the overhead already set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/688-pod-overhead/README.md' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + preemptionPolicy: + description: PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset. + type: string + priority: + description: The priority value. Various system components use this field to find the priority of the pod. When Priority Admission Controller is enabled, it prevents users from setting this field. The admission controller populates this field from PriorityClassName. The higher the value, the higher the priority. + type: integer + format: int32 + priorityClassName: + description: If specified, indicates the pod's priority. "system-node-critical" and "system-cluster-critical" are two special keywords which indicate the highest priorities with the former being the highest priority. Any other name must be defined by creating a PriorityClass object with that name. If not specified, the pod priority will be default or zero if there is no default. + type: string + readinessGates: + description: 'If specified, all readiness gates will be evaluated for pod readiness. A pod is ready when all its containers are ready AND all conditions specified in the readiness gates have status equal to "True" More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates' + type: array + items: + description: PodReadinessGate contains the reference to a pod condition + type: object + required: + - conditionType + properties: + conditionType: + description: ConditionType refers to a condition in the pod's condition list with matching type. + type: string + resourceClaims: + description: "ResourceClaims defines which ResourceClaims must be allocated and reserved before the Pod is allowed to start. The resources will be made available to those containers which consume them by name. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable." + type: array + items: + description: PodResourceClaim references exactly one ResourceClaim through a ClaimSource. It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. + type: object + required: + - name + properties: + name: + description: Name uniquely identifies this resource claim inside the pod. This must be a DNS_LABEL. + type: string + source: + description: Source describes where to find the ResourceClaim. + type: object + properties: + resourceClaimName: + description: ResourceClaimName is the name of a ResourceClaim object in the same namespace as this pod. + type: string + resourceClaimTemplateName: + description: "ResourceClaimTemplateName is the name of a ResourceClaimTemplate object in the same namespace as this pod. \n The template will be used to create a new ResourceClaim, which will be bound to this pod. When this pod is deleted, the ResourceClaim will also be deleted. The pod name and resource name, along with a generated component, will be used to form a unique name for the ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. \n This field is immutable and no changes will be made to the corresponding ResourceClaim by the control plane after creating the ResourceClaim." + type: string + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + restartPolicy: + description: 'Restart policy for all containers within the pod. One of Always, OnFailure, Never. In some contexts, only a subset of those values may be permitted. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy' + type: string + runtimeClassName: + description: 'RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/585-runtime-class' + type: string + schedulerName: + description: If specified, the pod will be dispatched by specified scheduler. If not specified, the pod will be dispatched by default scheduler. + type: string + schedulingGates: + description: "SchedulingGates is an opaque list of values that if specified will block scheduling the pod. If schedulingGates is not empty, the pod will stay in the SchedulingGated state and the scheduler will not attempt to schedule the pod. \n SchedulingGates can only be set at pod creation time, and be removed only afterwards. \n This is a beta feature enabled by the PodSchedulingReadiness feature gate." + type: array + items: + description: PodSchedulingGate is associated to a Pod to guard its scheduling. + type: object + required: + - name + properties: + name: + description: Name of the scheduling gate. Each scheduling gate must have a unique name field. + type: string + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + securityContext: + description: 'SecurityContext holds pod-level security attributes and common container settings. Optional: Defaults to empty. See type description for default values of each field.' + type: object + properties: + fsGroup: + description: "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod: \n 1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw---- \n If unset, the Kubelet will not modify the ownership and permissions of any volume. Note that this field cannot be set when spec.os.name is windows." + type: integer + format: int64 + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. Note that this field cannot be set when spec.os.name is windows.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the container process. Uses runtime default if unset. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. + type: integer + format: int64 + runAsNonRoot: + description: Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. + type: integer + format: int64 + seLinuxOptions: + description: The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container. Note that this field cannot be set when spec.os.name is windows. + type: object + properties: + level: + description: Level is SELinux level label that applies to the container. + type: string + role: + description: Role is a SELinux role label that applies to the container. + type: string + type: + description: Type is a SELinux type label that applies to the container. + type: string + user: + description: User is a SELinux user label that applies to the container. + type: string + seccompProfile: + description: The seccomp options to use by the containers in this pod. Note that this field cannot be set when spec.os.name is windows. + type: object + required: + - type + properties: + localhostProfile: + description: localhostProfile indicates a profile defined in a file on the node should be used. The profile must be preconfigured on the node to work. Must be a descending path, relative to the kubelet's configured seccomp profile location. Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: "type indicates which kind of seccomp profile will be applied. Valid options are: \n Localhost - a profile defined in a file on the node should be used. RuntimeDefault - the container runtime default profile should be used. Unconfined - no profile should be applied." + type: string + supplementalGroups: + description: A list of groups applied to the first process run in each container, in addition to the container's primary GID, the fsGroup (if specified), and group memberships defined in the container image for the uid of the container process. If unspecified, no additional groups are added to any container. Note that group memberships defined in the container image for the uid of the container process are still effective, even if they are not included in this list. Note that this field cannot be set when spec.os.name is windows. + type: array + items: + type: integer + format: int64 + sysctls: + description: Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported sysctls (by the container runtime) might fail to launch. Note that this field cannot be set when spec.os.name is windows. + type: array + items: + description: Sysctl defines a kernel parameter to be set + type: object + required: + - name + - value + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + windowsOptions: + description: The Windows specific settings applied to all containers. If unspecified, the options within a container's SecurityContext will be used. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. Note that this field cannot be set when spec.os.name is linux. + type: object + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container should be run as a 'Host Process' container. All of a Pod's containers must have the same effective HostProcess value (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: The UserName in Windows to run the entrypoint of the container process. Defaults to the user specified in image metadata if unspecified. May also be set in PodSecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + serviceAccount: + description: 'DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. Deprecated: Use serviceAccountName instead.' + type: string + serviceAccountName: + description: 'ServiceAccountName is the name of the ServiceAccount to use to run this pod. More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/' + type: string + setHostnameAsFQDN: + description: If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. If a pod does not have FQDN, this has no effect. Default to false. + type: boolean + shareProcessNamespace: + description: 'Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false.' + type: boolean + subdomain: + description: If specified, the fully qualified Pod hostname will be "...svc.". If not specified, the pod will not have a domainname at all. + type: string + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). If this value is nil, the default grace period will be used instead. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. Defaults to 30 seconds. + type: integer + format: int64 + tolerations: + description: If specified, the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + topologySpreadConstraints: + description: TopologySpreadConstraints describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints. All topologySpreadConstraints are ANDed. + type: array + items: + description: TopologySpreadConstraint specifies how to spread matching pods among the given topology. + type: object + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + properties: + labelSelector: + description: LabelSelector is used to find matching pods. Pods that match this label selector are counted to determine the number of pods in their corresponding topology domain. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + matchLabelKeys: + description: "MatchLabelKeys is a set of pod label keys to select the pods over which spreading will be calculated. The keys are used to lookup values from the incoming pod labels, those key-value labels are ANDed with labelSelector to select the group of existing pods over which spreading will be calculated for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. MatchLabelKeys cannot be set when LabelSelector isn't set. Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against labelSelector. \n This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default)." + type: array + items: + type: string + x-kubernetes-list-type: atomic + maxSkew: + description: 'MaxSkew describes the degree to which pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference between the number of matching pods in the target topology and the global minimum. The global minimum is the minimum number of matching pods in an eligible domain or zero if the number of eligible domains is less than MinDomains. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 2/2/1: In this case, the global minimum is 1. | zone1 | zone2 | zone3 | | P P | P P | P | - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) violate MaxSkew(1). - if MaxSkew is 2, incoming pod can be scheduled onto any zone. When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence to topologies that satisfy it. It''s a required field. Default value is 1 and 0 is not allowed.' + type: integer + format: int32 + minDomains: + description: "MinDomains indicates a minimum number of eligible domains. When the number of eligible domains with matching topology keys is less than minDomains, Pod Topology Spread treats \"global minimum\" as 0, and then the calculation of Skew is performed. And when the number of eligible domains with matching topology keys equals or greater than minDomains, this value has no effect on scheduling. As a result, when the number of eligible domains is less than minDomains, scheduler won't schedule more than maxSkew Pods to those domains. If value is nil, the constraint behaves as if MinDomains is equal to 1. Valid values are integers greater than 0. When value is not nil, WhenUnsatisfiable must be DoNotSchedule. \n For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same labelSelector spread as 2/2/2: | zone1 | zone2 | zone3 | | P P | P P | P P | The number of domains is less than 5(MinDomains), so \"global minimum\" is treated as 0. In this situation, new pod with the same labelSelector cannot be scheduled, because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, it will violate MaxSkew. \n This is a beta field and requires the MinDomainsInPodTopologySpread feature gate to be enabled (enabled by default)." + type: integer + format: int32 + nodeAffinityPolicy: + description: "NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. \n If this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag." + type: string + nodeTaintsPolicy: + description: "NodeTaintsPolicy indicates how we will treat node taints when calculating pod topology spread skew. Options are: - Honor: nodes without taints, along with tainted nodes for which the incoming pod has a toleration, are included. - Ignore: node taints are ignored. All nodes are included. \n If this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag." + type: string + topologyKey: + description: TopologyKey is the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology. We consider each as a "bucket", and try to put balanced number of pods into each bucket. We define a domain as a particular instance of a topology. Also, we define an eligible domain as a domain whose nodes meet the requirements of nodeAffinityPolicy and nodeTaintsPolicy. e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. It's a required field. + type: string + whenUnsatisfiable: + description: 'WhenUnsatisfiable indicates how to deal with a pod if it doesn''t satisfy the spread constraint. - DoNotSchedule (default) tells the scheduler not to schedule it. - ScheduleAnyway tells the scheduler to schedule the pod in any location, but giving higher precedence to topologies that would help reduce the skew. A constraint is considered "Unsatisfiable" for an incoming pod if and only if every possible node assignment for that pod would violate "MaxSkew" on some topology. For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same labelSelector spread as 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler won''t make it *more* imbalanced. It''s a required field.' + type: string + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + volumes: + description: 'List of volumes that can be mounted by containers belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes' + type: array + items: + description: Volume represents a named volume in a pod that may be accessed by any container in the pod. + type: object + required: + - name + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: object + required: + - volumeID + properties: + fsType: + description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty).' + type: integer + format: int32 + readOnly: + description: 'readOnly value true will force the readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + azureDisk: + description: azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + type: object + required: + - diskName + - diskURI + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + azureFile: + description: azureFile represents an Azure File Service mount on the host and bind mount to the pod. + type: object + required: + - secretName + - shareName + properties: + readOnly: + description: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + cephfs: + description: cephFS represents a Ceph FS mount on the host that shares a pod's lifetime + type: object + required: + - monitors + properties: + monitors: + description: 'monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: array + items: + type: string + path: + description: 'path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + user: + description: 'user is optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + cinder: + description: 'cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: object + required: + - volumeID + properties: + fsType: + description: 'fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a secret object containing parameters used to connect to OpenStack.' + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + volumeID: + description: 'volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + configMap: + description: configMap represents a configMap that should populate this volume + type: object + properties: + defaultMode: + description: 'defaultMode is optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + items: + description: items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. + type: array + items: + description: Maps a string key to a path within a volume. + type: object + required: + - key + - path + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap or its keys must be defined + type: boolean + csi: + description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). + type: object + required: + - driver + properties: + driver: + description: driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", "ntfs". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed. + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + readOnly: + description: readOnly specifies a read-only configuration for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + description: volumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values. + type: object + additionalProperties: + type: string + downwardAPI: + description: downwardAPI represents downward API about the pod that should populate this volume + type: object + properties: + defaultMode: + description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + items: + description: Items is a list of downward API volume file + type: array + items: + description: DownwardAPIVolumeFile represents information to create the file containing the pod field + type: object + required: + - path + properties: + fieldRef: + description: 'Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.' + type: object + required: + - fieldPath + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + mode: + description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: 'Required: Path is the relative path name of the file to be created. Must not be absolute or contain the ''..'' path. Must be utf-8 encoded. The first item of the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.' + type: object + required: + - resource + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + emptyDir: + description: 'emptyDir represents a temporary directory that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: object + properties: + medium: + description: 'medium represents what type of storage medium should back this directory. The default is "" which means to use the node''s default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + description: 'sizeLimit is the total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + ephemeral: + description: "ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. \n Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. \n Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes at the same time." + type: object + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be `-` where `` is the name from the `PodSpec.Volumes` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). \n An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. \n This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. \n Required, must not be nil." + type: object + required: + - spec + properties: + metadata: + description: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here. + type: object + properties: + accessModes: + description: 'accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + type: array + items: + type: string + dataSource: + description: 'dataSource field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. If the namespace is specified, then dataSourceRef will not be copied to dataSource.' + type: object + required: + - kind + - name + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + dataSourceRef: + description: 'dataSourceRef specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. This field will replace the functionality of the dataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, when namespace isn''t specified in dataSourceRef, both fields (dataSource and dataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. When namespace is specified in dataSourceRef, dataSource isn''t set to the same value and must be empty. There are three important differences between dataSource and dataSourceRef: * While dataSource only allows two specific types of objects, dataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. * While dataSource ignores disallowed values (dropping them), dataSourceRef preserves all values, and generates an error if a disallowed value is specified. * While dataSource only allows local objects, dataSourceRef allows objects in any namespaces. (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled.' + type: object + required: + - kind + - name + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being referenced Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + resources: + description: 'resources represents the minimum resources the volume should have. If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements that are lower than previous value but must still be higher than capacity recorded in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + type: object + properties: + claims: + description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable. It can only be set for containers." + type: array + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + type: object + required: + - name + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. + type: string + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + requests: + description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selector: + description: selector is a label query over volumes to consider for binding. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + storageClassName: + description: 'storageClassName is the name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference to the PersistentVolume backing this claim. + type: string + fc: + description: fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + type: object + properties: + fsType: + description: 'fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + type: integer + format: int32 + readOnly: + description: 'readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide names (WWNs)' + type: array + items: + type: string + wwids: + description: 'wwids Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously.' + type: array + items: + type: string + flexVolume: + description: flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. + type: object + required: + - driver + properties: + driver: + description: driver is the name of the driver to use for this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + type: string + options: + description: 'options is Optional: this field holds extra command options if any.' + type: object + additionalProperties: + type: string + readOnly: + description: 'readOnly is Optional: defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.' + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + flocker: + description: flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running + type: object + properties: + datasetName: + description: datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset + type: string + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: object + required: + - pdName + properties: + fsType: + description: 'fsType is filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: integer + format: int32 + pdName: + description: 'pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + gitRepo: + description: 'gitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod''s container.' + type: object + required: + - repository + properties: + directory: + description: directory is the target directory name. Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified revision. + type: string + glusterfs: + description: 'glusterfs represents a Glusterfs mount on the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + type: object + required: + - endpoints + - path + properties: + endpoints: + description: 'endpoints is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + hostPath: + description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath --- TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not mount host directories as read/write.' + type: object + required: + - path + properties: + path: + description: 'path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + iscsi: + description: 'iscsi represents an ISCSI Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + type: object + required: + - iqn + - lun + - targetPortal + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + type: integer + format: int32 + portals: + description: portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). + type: array + items: + type: string + readOnly: + description: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI target and initiator authentication + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + targetPortal: + description: targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). + type: string + name: + description: 'name of the volume. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: object + required: + - path + - server + properties: + path: + description: 'path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: object + required: + - claimName + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting in VolumeMounts. Default false. + type: boolean + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine + type: object + required: + - pdID + properties: + fsType: + description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller persistent disk + type: string + portworxVolume: + description: portworxVolume represents a portworx volume attached and mounted on kubelets host machine + type: object + required: + - volumeID + properties: + fsType: + description: fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx volume + type: string + projected: + description: projected items for all in one resources secrets, configmaps, and downward API + type: object + properties: + defaultMode: + description: defaultMode are the mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. + type: integer + format: int32 + sources: + description: sources is the list of volume projections + type: array + items: + description: Projection that may be projected along with other supported volume types + type: object + properties: + configMap: + description: configMap information about the configMap data to project + type: object + properties: + items: + description: items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. + type: array + items: + description: Maps a string key to a path within a volume. + type: object + required: + - key + - path + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap or its keys must be defined + type: boolean + downwardAPI: + description: downwardAPI information about the downwardAPI data to project + type: object + properties: + items: + description: Items is a list of DownwardAPIVolume file + type: array + items: + description: DownwardAPIVolumeFile represents information to create the file containing the pod field + type: object + required: + - path + properties: + fieldRef: + description: 'Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.' + type: object + required: + - fieldPath + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + mode: + description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: 'Required: Path is the relative path name of the file to be created. Must not be absolute or contain the ''..'' path. Must be utf-8 encoded. The first item of the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.' + type: object + required: + - resource + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + secret: + description: secret information about the secret data to project + type: object + properties: + items: + description: items if unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. + type: array + items: + description: Maps a string key to a path within a volume. + type: object + required: + - key + - path + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional field specify whether the Secret or its key must be defined + type: boolean + serviceAccountToken: + description: serviceAccountToken is information about the serviceAccountToken data to project + type: object + required: + - path + properties: + audience: + description: audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. The audience defaults to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet volume plugin will proactively rotate the service account token. The kubelet will start trying to rotate the token if the token is older than 80 percent of its time to live or if the token is older than 24 hours.Defaults to 1 hour and must be at least 10 minutes. + type: integer + format: int64 + path: + description: path is the path relative to the mount point of the file to project the token into. + type: string + quobyte: + description: quobyte represents a Quobyte mount on the host that shares a pod's lifetime + type: object + required: + - registry + - volume + properties: + group: + description: group to map volume access to Default is no group + type: string + readOnly: + description: readOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references an already created Quobyte volume by name. + type: string + rbd: + description: 'rbd represents a Rados Block Device mount on the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' + type: object + required: + - image + - monitors + properties: + fsType: + description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + image: + description: 'image is the rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: array + items: + type: string + pool: + description: 'pool is the rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + user: + description: 'user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + scaleIO: + description: scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + type: object + required: + - gateway + - secretRef + - system + properties: + fsType: + description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail. + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source. + type: string + secret: + description: 'secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: object + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + items: + description: items If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. + type: array + items: + description: Maps a string key to a path within a volume. + type: object + required: + - key + - path + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + type: string + optional: + description: optional field specify whether the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + storageos: + description: storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. + type: object + properties: + fsType: + description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted. + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + volumeName: + description: volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to "default" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created. + type: string + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine + type: object + required: + - volumePath + properties: + fsType: + description: fsType is filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies vSphere volume vmdk + type: string + permissions: + type: array + items: + description: StrategyDeploymentPermissions describe the rbac rules and service account needed by the install strategy + type: object + required: + - rules + - serviceAccountName + properties: + rules: + type: array + items: + description: PolicyRule holds information that describes a policy rule, but does not contain information about who the rule applies to or which namespace the rule applies to. + type: object + required: + - verbs + properties: + apiGroups: + description: APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of the enumerated resources in any API group will be allowed. "" represents the core API group and "*" represents all API groups. + type: array + items: + type: string + nonResourceURLs: + description: NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. + type: array + items: + type: string + resourceNames: + description: ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + type: array + items: + type: string + resources: + description: Resources is a list of resources this rule applies to. '*' represents all resources. + type: array + items: + type: string + verbs: + description: Verbs is a list of Verbs that apply to ALL the ResourceKinds contained in this rule. '*' represents all verbs. + type: array + items: + type: string + serviceAccountName: + type: string + strategy: + type: string + installModes: + description: InstallModes specify supported installation types + type: array + items: + description: InstallMode associates an InstallModeType with a flag representing if the CSV supports it + type: object + required: + - supported + - type + properties: + supported: + type: boolean + type: + description: InstallModeType is a supported type of install mode for CSV installation + type: string + keywords: + description: A list of keywords describing the operator. + type: array + items: + type: string + labels: + description: Map of string keys and values that can be used to organize and categorize (scope and select) objects. + type: object + additionalProperties: + type: string + links: + description: A list of links related to the operator. + type: array + items: + type: object + properties: + name: + type: string + url: + type: string + maintainers: + description: A list of organizational entities maintaining the operator. + type: array + items: + type: object + properties: + email: + type: string + name: + type: string + maturity: + type: string + minKubeVersion: + type: string + nativeAPIs: + type: array + items: + description: GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling + type: object + required: + - group + - kind + - version + properties: + group: + type: string + kind: + type: string + version: + type: string + provider: + description: The publishing entity behind the operator. + type: object + properties: + name: + type: string + url: + type: string + relatedImages: + description: List any related images, or other container images that your Operator might require to perform their functions. This list should also include operand images as well. All image references should be specified by digest (SHA) and not by tag. This field is only used during catalog creation and plays no part in cluster runtime. + type: array + items: + type: object + required: + - image + - name + properties: + image: + type: string + name: + type: string + replaces: + description: The name of a CSV this one replaces. Should match the `metadata.Name` field of the old CSV. + type: string + selector: + description: Label selector for related resources. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + skips: + description: The name(s) of one or more CSV(s) that should be skipped in the upgrade graph. Should match the `metadata.Name` field of the CSV that should be skipped. This field is only used during catalog creation and plays no part in cluster runtime. + type: array + items: + type: string + version: + type: string + webhookdefinitions: + type: array + items: + description: WebhookDescription provides details to OLM about required webhooks + type: object + required: + - admissionReviewVersions + - generateName + - sideEffects + - type + properties: + admissionReviewVersions: + type: array + items: + type: string + containerPort: + type: integer + format: int32 + default: 443 + maximum: 65535 + minimum: 1 + conversionCRDs: + type: array + items: + type: string + deploymentName: + type: string + failurePolicy: + description: FailurePolicyType specifies a failure policy that defines how unrecognized errors from the admission endpoint are handled. + type: string + generateName: + type: string + matchPolicy: + description: MatchPolicyType specifies the type of match policy. + type: string + objectSelector: + description: A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + reinvocationPolicy: + description: ReinvocationPolicyType specifies what type of policy the admission hook uses. + type: string + rules: + type: array + items: + description: RuleWithOperations is a tuple of Operations and Resources. It is recommended to make sure that all the tuple expansions are valid. + type: object + properties: + apiGroups: + description: APIGroups is the API groups the resources belong to. '*' is all groups. If '*' is present, the length of the slice must be one. Required. + type: array + items: + type: string + x-kubernetes-list-type: atomic + apiVersions: + description: APIVersions is the API versions the resources belong to. '*' is all versions. If '*' is present, the length of the slice must be one. Required. + type: array + items: + type: string + x-kubernetes-list-type: atomic + operations: + description: Operations is the operations the admission hook cares about - CREATE, UPDATE, DELETE, CONNECT or * for all of those operations and any future admission operations that are added. If '*' is present, the length of the slice must be one. Required. + type: array + items: + description: OperationType specifies an operation for a request. + type: string + x-kubernetes-list-type: atomic + resources: + description: "Resources is a list of resources this rule applies to. \n For example: 'pods' means pods. 'pods/log' means the log subresource of pods. '*' means all resources, but not subresources. 'pods/*' means all subresources of pods. '*/scale' means all scale subresources. '*/*' means all resources and their subresources. \n If wildcard is present, the validation rule will ensure resources do not overlap with each other. \n Depending on the enclosing object, subresources might not be allowed. Required." + type: array + items: + type: string + x-kubernetes-list-type: atomic + scope: + description: scope specifies the scope of this rule. Valid values are "Cluster", "Namespaced", and "*" "Cluster" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. "Namespaced" means that only namespaced resources will match this rule. "*" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is "*". + type: string + sideEffects: + description: SideEffectClass specifies the types of side effects a webhook may have. + type: string + targetPort: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + timeoutSeconds: + type: integer + format: int32 + type: + description: WebhookAdmissionType is the type of admission webhooks supported by OLM + type: string + enum: + - ValidatingAdmissionWebhook + - MutatingAdmissionWebhook + - ConversionWebhook + webhookPath: + type: string + status: + description: ClusterServiceVersionStatus represents information about the status of a CSV. Status may trail the actual state of a system. + type: object + properties: + certsLastUpdated: + description: Last time the owned APIService certs were updated + type: string + format: date-time + certsRotateAt: + description: Time the owned APIService certs will rotate next + type: string + format: date-time + cleanup: + description: CleanupStatus represents information about the status of cleanup while a CSV is pending deletion + type: object + properties: + pendingDeletion: + description: PendingDeletion is the list of custom resource objects that are pending deletion and blocked on finalizers. This indicates the progress of cleanup that is blocking CSV deletion or operator uninstall. + type: array + items: + description: ResourceList represents a list of resources which are of the same Group/Kind + type: object + required: + - group + - instances + - kind + properties: + group: + type: string + instances: + type: array + items: + type: object + required: + - name + properties: + name: + type: string + namespace: + description: Namespace can be empty for cluster-scoped resources + type: string + kind: + type: string + conditions: + description: List of conditions, a history of state transitions + type: array + items: + description: Conditions appear in the status as a record of state transitions on the ClusterServiceVersion + type: object + properties: + lastTransitionTime: + description: Last time the status transitioned from one status to another. + type: string + format: date-time + lastUpdateTime: + description: Last time we updated the status + type: string + format: date-time + message: + description: A human readable message indicating details about why the ClusterServiceVersion is in this condition. + type: string + phase: + description: Condition of the ClusterServiceVersion + type: string + reason: + description: A brief CamelCase message indicating details about why the ClusterServiceVersion is in this state. e.g. 'RequirementsNotMet' + type: string + lastTransitionTime: + description: Last time the status transitioned from one status to another. + type: string + format: date-time + lastUpdateTime: + description: Last time we updated the status + type: string + format: date-time + message: + description: A human readable message indicating details about why the ClusterServiceVersion is in this condition. + type: string + phase: + description: Current condition of the ClusterServiceVersion + type: string + reason: + description: A brief CamelCase message indicating details about why the ClusterServiceVersion is in this state. e.g. 'RequirementsNotMet' + type: string + requirementStatus: + description: The status of each requirement for this CSV + type: array + items: + type: object + required: + - group + - kind + - message + - name + - status + - version + properties: + dependents: + type: array + items: + description: DependentStatus is the status for a dependent requirement (to prevent infinite nesting) + type: object + required: + - group + - kind + - status + - version + properties: + group: + type: string + kind: + type: string + message: + type: string + status: + description: StatusReason is a camelcased reason for the status of a RequirementStatus or DependentStatus + type: string + uuid: + type: string + version: + type: string + group: + type: string + kind: + type: string + message: + type: string + name: + type: string + status: + description: StatusReason is a camelcased reason for the status of a RequirementStatus or DependentStatus + type: string + uuid: + type: string + version: + type: string + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: installplans.operators.coreos.com +spec: + group: operators.coreos.com + names: + categories: + - olm + kind: InstallPlan + listKind: InstallPlanList + plural: installplans + shortNames: + - ip + singular: installplan + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The first CSV in the list of clusterServiceVersionNames + jsonPath: .spec.clusterServiceVersionNames[0] + name: CSV + type: string + - description: The approval mode + jsonPath: .spec.approval + name: Approval + type: string + - jsonPath: .spec.approved + name: Approved + type: boolean + name: v1alpha1 + schema: + openAPIV3Schema: + description: InstallPlan defines the installation of a set of operators. + type: object + required: + - metadata + - spec + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: InstallPlanSpec defines a set of Application resources to be installed + type: object + required: + - approval + - approved + - clusterServiceVersionNames + properties: + approval: + description: Approval is the user approval policy for an InstallPlan. It must be one of "Automatic" or "Manual". + type: string + approved: + type: boolean + clusterServiceVersionNames: + type: array + items: + type: string + generation: + type: integer + source: + type: string + sourceNamespace: + type: string + status: + description: "InstallPlanStatus represents the information about the status of steps required to complete installation. \n Status may trail the actual state of a system." + type: object + required: + - catalogSources + - phase + properties: + attenuatedServiceAccountRef: + description: AttenuatedServiceAccountRef references the service account that is used to do scoped operator install. + type: object + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + bundleLookups: + description: BundleLookups is the set of in-progress requests to pull and unpackage bundle content to the cluster. + type: array + items: + description: BundleLookup is a request to pull and unpackage the content of a bundle to the cluster. + type: object + required: + - catalogSourceRef + - identifier + - path + - replaces + properties: + catalogSourceRef: + description: CatalogSourceRef is a reference to the CatalogSource the bundle path was resolved from. + type: object + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + conditions: + description: Conditions represents the overall state of a BundleLookup. + type: array + items: + type: object + required: + - status + - type + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + format: date-time + lastUpdateTime: + description: Last time the condition was probed. + type: string + format: date-time + message: + description: A human readable message indicating details about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition. + type: string + identifier: + description: Identifier is the catalog-unique name of the operator (the name of the CSV for bundles that contain CSVs) + type: string + path: + description: Path refers to the location of a bundle to pull. It's typically an image reference. + type: string + properties: + description: The effective properties of the unpacked bundle. + type: string + replaces: + description: Replaces is the name of the bundle to replace with the one found at Path. + type: string + catalogSources: + type: array + items: + type: string + conditions: + type: array + items: + description: InstallPlanCondition represents the overall status of the execution of an InstallPlan. + type: object + properties: + lastTransitionTime: + type: string + format: date-time + lastUpdateTime: + type: string + format: date-time + message: + type: string + reason: + description: ConditionReason is a camelcased reason for the state transition. + type: string + status: + type: string + type: + description: InstallPlanConditionType describes the state of an InstallPlan at a certain point as a whole. + type: string + message: + description: Message is a human-readable message containing detailed information that may be important to understanding why the plan has its current status. + type: string + phase: + description: InstallPlanPhase is the current status of a InstallPlan as a whole. + type: string + plan: + type: array + items: + description: Step represents the status of an individual step in an InstallPlan. + type: object + required: + - resolving + - resource + - status + properties: + optional: + type: boolean + resolving: + type: string + resource: + description: StepResource represents the status of a resource to be tracked by an InstallPlan. + type: object + required: + - group + - kind + - name + - sourceName + - sourceNamespace + - version + properties: + group: + type: string + kind: + type: string + manifest: + type: string + name: + type: string + sourceName: + type: string + sourceNamespace: + type: string + version: + type: string + status: + description: StepStatus is the current status of a particular resource an in InstallPlan + type: string + startTime: + description: StartTime is the time when the controller began applying the resources listed in the plan to the cluster. + type: string + format: date-time + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: olmconfigs.operators.coreos.com +spec: + group: operators.coreos.com + names: + categories: + - olm + kind: OLMConfig + listKind: OLMConfigList + plural: olmconfigs + singular: olmconfig + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OLMConfig is a resource responsible for configuring OLM. + type: object + required: + - metadata + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OLMConfigSpec is the spec for an OLMConfig resource. + type: object + properties: + features: + description: Features contains the list of configurable OLM features. + type: object + properties: + disableCopiedCSVs: + description: DisableCopiedCSVs is used to disable OLM's "Copied CSV" feature for operators installed at the cluster scope, where a cluster scoped operator is one that has been installed in an OperatorGroup that targets all namespaces. When reenabled, OLM will recreate the "Copied CSVs" for each cluster scoped operator. + type: boolean + packageServerSyncInterval: + description: PackageServerSyncInterval is used to define the sync interval for packagerserver pods. Packageserver pods periodically check the status of CatalogSources; this specifies the period using duration format (e.g. "60m"). For this parameter, only hours ("h"), minutes ("m"), and seconds ("s") may be specified. When not specified, the period defaults to the value specified within the packageserver. + type: string + pattern: ^([0-9]+(\.[0-9]+)?(s|m|h))+$ + status: + description: OLMConfigStatus is the status for an OLMConfig resource. + type: object + properties: + conditions: + type: array + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + type: object + required: + - lastTransitionTime + - message + - reason + - status + - type + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + type: string + format: date-time + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + type: string + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + type: integer + format: int64 + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. + type: string + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + type: string + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: operatorconditions.operators.coreos.com +spec: + group: operators.coreos.com + names: + categories: + - olm + kind: OperatorCondition + listKind: OperatorConditionList + plural: operatorconditions + shortNames: + - condition + singular: operatorcondition + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OperatorCondition is a Custom Resource of type `OperatorCondition` which is used to convey information to OLM about the state of an operator. + type: object + required: + - metadata + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OperatorConditionSpec allows a cluster admin to convey information about the state of an operator to OLM, potentially overriding state reported by the operator. + type: object + properties: + deployments: + type: array + items: + type: string + overrides: + type: array + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + type: object + required: + - message + - reason + - status + - type + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + type: string + format: date-time + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + type: string + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + type: integer + format: int64 + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. + type: string + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + type: string + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + serviceAccounts: + type: array + items: + type: string + status: + description: OperatorConditionStatus allows an operator to convey information its state to OLM. The status may trail the actual state of a system. + type: object + properties: + conditions: + type: array + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + type: object + required: + - lastTransitionTime + - message + - reason + - status + - type + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + type: string + format: date-time + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + type: string + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + type: integer + format: int64 + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. + type: string + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + type: string + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + served: true + storage: false + subresources: + status: {} + - name: v2 + schema: + openAPIV3Schema: + description: OperatorCondition is a Custom Resource of type `OperatorCondition` which is used to convey information to OLM about the state of an operator. + type: object + required: + - metadata + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OperatorConditionSpec allows an operator to report state to OLM and provides cluster admin with the ability to manually override state reported by the operator. + type: object + properties: + conditions: + type: array + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + type: object + required: + - lastTransitionTime + - message + - reason + - status + - type + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + type: string + format: date-time + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + type: string + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + type: integer + format: int64 + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. + type: string + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + type: string + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + deployments: + type: array + items: + type: string + overrides: + type: array + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + type: object + required: + - message + - reason + - status + - type + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + type: string + format: date-time + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + type: string + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + type: integer + format: int64 + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. + type: string + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + type: string + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + serviceAccounts: + type: array + items: + type: string + status: + description: OperatorConditionStatus allows OLM to convey which conditions have been observed. + type: object + properties: + conditions: + type: array + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + type: object + required: + - lastTransitionTime + - message + - reason + - status + - type + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + type: string + format: date-time + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + type: string + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + type: integer + format: int64 + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. + type: string + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + type: string + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: operatorgroups.operators.coreos.com +spec: + group: operators.coreos.com + names: + categories: + - olm + kind: OperatorGroup + listKind: OperatorGroupList + plural: operatorgroups + shortNames: + - og + singular: operatorgroup + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: OperatorGroup is the unit of multitenancy for OLM managed operators. It constrains the installation of operators in its namespace to a specified set of target namespaces. + type: object + required: + - metadata + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OperatorGroupSpec is the spec for an OperatorGroup resource. + type: object + default: + upgradeStrategy: Default + properties: + selector: + description: Selector selects the OperatorGroup's target namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + serviceAccountName: + description: ServiceAccountName is the admin specified service account which will be used to deploy operator(s) in this operator group. + type: string + staticProvidedAPIs: + description: Static tells OLM not to update the OperatorGroup's providedAPIs annotation + type: boolean + targetNamespaces: + description: TargetNamespaces is an explicit set of namespaces to target. If it is set, Selector is ignored. + type: array + items: + type: string + x-kubernetes-list-type: set + upgradeStrategy: + description: "UpgradeStrategy defines the upgrade strategy for operators in the namespace. There are currently two supported upgrade strategies: \n Default: OLM will only allow clusterServiceVersions to move to the replacing phase from the succeeded phase. This effectively means that OLM will not allow operators to move to the next version if an installation or upgrade has failed. \n TechPreviewUnsafeFailForward: OLM will allow clusterServiceVersions to move to the replacing phase from the succeeded phase or from the failed phase. Additionally, OLM will generate new installPlans when a subscription references a failed installPlan and the catalog has been updated with a new upgrade for the existing set of operators. \n WARNING: The TechPreviewUnsafeFailForward upgrade strategy is unsafe and may result in unexpected behavior or unrecoverable data loss unless you have deep understanding of the set of operators being managed in the namespace." + type: string + default: Default + enum: + - Default + - TechPreviewUnsafeFailForward + status: + description: OperatorGroupStatus is the status for an OperatorGroupResource. + type: object + required: + - lastUpdated + properties: + conditions: + description: Conditions is an array of the OperatorGroup's conditions. + type: array + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, \n type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + type: object + required: + - lastTransitionTime + - message + - reason + - status + - type + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + type: string + format: date-time + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + type: string + maxLength: 32768 + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + type: integer + format: int64 + minimum: 0 + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + type: string + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + status: + description: status of the condition, one of True, False, Unknown. + type: string + enum: + - "True" + - "False" + - Unknown + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + type: string + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + lastUpdated: + description: LastUpdated is a timestamp of the last time the OperatorGroup's status was Updated. + type: string + format: date-time + namespaces: + description: Namespaces is the set of target namespaces for the OperatorGroup. + type: array + items: + type: string + x-kubernetes-list-type: set + serviceAccountRef: + description: ServiceAccountRef references the service account object specified. + type: object + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + served: true + storage: true + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: OperatorGroup is the unit of multitenancy for OLM managed operators. It constrains the installation of operators in its namespace to a specified set of target namespaces. + type: object + required: + - metadata + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OperatorGroupSpec is the spec for an OperatorGroup resource. + type: object + properties: + selector: + description: Selector selects the OperatorGroup's target namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + serviceAccountName: + description: ServiceAccountName is the admin specified service account which will be used to deploy operator(s) in this operator group. + type: string + staticProvidedAPIs: + description: Static tells OLM not to update the OperatorGroup's providedAPIs annotation + type: boolean + targetNamespaces: + description: TargetNamespaces is an explicit set of namespaces to target. If it is set, Selector is ignored. + type: array + items: + type: string + status: + description: OperatorGroupStatus is the status for an OperatorGroupResource. + type: object + required: + - lastUpdated + properties: + lastUpdated: + description: LastUpdated is a timestamp of the last time the OperatorGroup's status was Updated. + type: string + format: date-time + namespaces: + description: Namespaces is the set of target namespaces for the OperatorGroup. + type: array + items: + type: string + serviceAccountRef: + description: ServiceAccountRef references the service account object specified. + type: object + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + served: true + storage: false + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: operators.operators.coreos.com +spec: + group: operators.coreos.com + names: + categories: + - olm + kind: Operator + listKind: OperatorList + plural: operators + singular: operator + scope: Cluster + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Operator represents a cluster operator. + type: object + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: OperatorSpec defines the desired state of Operator + type: object + status: + description: OperatorStatus defines the observed state of an Operator and its components + type: object + properties: + components: + description: Components describes resources that compose the operator. + type: object + required: + - labelSelector + properties: + labelSelector: + description: LabelSelector is a label query over a set of resources used to select the operator's components + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + refs: + description: Refs are a set of references to the operator's component resources, selected with LabelSelector. + type: array + items: + description: RichReference is a reference to a resource, enriched with its status conditions. + type: object + properties: + apiVersion: + description: API version of the referent. + type: string + conditions: + description: Conditions represents the latest state of the component. + type: array + items: + description: Condition represent the latest available observations of an component's state. + type: object + required: + - status + - type + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + type: string + format: date-time + lastUpdateTime: + description: Last time the condition was probed + type: string + format: date-time + message: + description: A human readable message indicating details about the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.0 + creationTimestamp: null + name: subscriptions.operators.coreos.com +spec: + group: operators.coreos.com + names: + categories: + - olm + kind: Subscription + listKind: SubscriptionList + plural: subscriptions + shortNames: + - sub + - subs + singular: subscription + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The package subscribed to + jsonPath: .spec.name + name: Package + type: string + - description: The catalog source for the specified package + jsonPath: .spec.source + name: Source + type: string + - description: The channel of updates to subscribe to + jsonPath: .spec.channel + name: Channel + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Subscription keeps operators up to date by tracking changes to Catalogs. + type: object + required: + - metadata + - spec + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: SubscriptionSpec defines an Application that can be installed + type: object + required: + - name + - source + - sourceNamespace + properties: + channel: + type: string + config: + description: SubscriptionConfig contains configuration specified for a subscription. + type: object + properties: + affinity: + description: If specified, overrides the pod's scheduling constraints. nil sub-attributes will *not* override the original values in the pod.spec for those sub-attributes. Use empty object ({}) to erase original sub-attribute values. + type: object + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + type: array + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + type: object + required: + - preference + - weight + properties: + preference: + description: A node selector term, associated with the corresponding weight. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + type: object + required: + - nodeSelectorTerms + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + type: array + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + type: object + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchFields: + description: A list of node selector requirements by node's fields. + type: array + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + type: array + items: + type: string + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + type: object + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + type: array + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + type: object + required: + - podAffinityTerm + - weight + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + type: integer + format: int32 + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + type: array + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + type: object + required: + - topologyKey + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace". + type: array + items: + type: string + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + annotations: + description: Annotations is an unstructured key value map stored with each Deployment, Pod, APIService in the Operator. Typically, annotations may be set by external tools to store and retrieve arbitrary metadata. Use this field to pre-define annotations that OLM should add to each of the Subscription's deployments, pods, and apiservices. + type: object + additionalProperties: + type: string + env: + description: Env is a list of environment variables to set in the container. Cannot be updated. + type: array + items: + description: EnvVar represents an environment variable present in a Container. + type: object + required: + - name + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot be used if value is not empty. + type: object + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + type: object + required: + - key + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key must be defined + type: boolean + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.' + type: object + required: + - fieldPath + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.' + type: object + required: + - resource + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + type: object + required: + - key + properties: + key: + description: The key of the secret to select from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + envFrom: + description: EnvFrom is a list of sources to populate environment variables in the container. The keys defined within a source must be a C_IDENTIFIER. All invalid keys will be reported as an event when the container is starting. When a key exists in multiple sources, the value associated with the last source will take precedence. Values defined by an Env with a duplicate key will take precedence. Immutable. + type: array + items: + description: EnvFromSource represents the source of a set of ConfigMaps + type: object + properties: + configMapRef: + description: The ConfigMap to select from + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap must be defined + type: boolean + prefix: + description: An optional identifier to prepend to each key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + nodeSelector: + description: 'NodeSelector is a selector which must be true for the pod to fit on a node. Selector which must match a node''s labels for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + additionalProperties: + type: string + resources: + description: 'Resources represents compute resources required by this container. Immutable. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + properties: + claims: + description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable. It can only be set for containers." + type: array + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + type: object + required: + - name + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. + type: string + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + requests: + description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selector: + description: Selector is the label selector for pods to be configured. Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment. It must match the pod template's labels. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + tolerations: + description: Tolerations are the pod's tolerations. + type: array + items: + description: The pod this Toleration is attached to tolerates any taint that matches the triple using the matching operator . + type: object + properties: + effect: + description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time the toleration (which must be of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, it is not set, which means tolerate the taint forever (do not evict). Zero and negative values will be treated as 0 (evict immediately) by the system. + type: integer + format: int64 + value: + description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + volumeMounts: + description: List of VolumeMounts to set in the container. + type: array + items: + description: VolumeMount describes a mounting of a Volume within a container. + type: object + required: + - mountPath + - name + properties: + mountPath: + description: Path within the container at which the volume should be mounted. Must not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume from which the container's volume should be mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume from which the container's volume should be mounted. Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. Defaults to "" (volume's root). SubPathExpr and SubPath are mutually exclusive. + type: string + volumes: + description: List of Volumes to set in the podSpec. + type: array + items: + description: Volume represents a named volume in a pod that may be accessed by any container in the pod. + type: object + required: + - name + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents an AWS Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: object + required: + - volumeID + properties: + fsType: + description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty).' + type: integer + format: int32 + readOnly: + description: 'readOnly value true will force the readOnly setting in VolumeMounts. More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + azureDisk: + description: azureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. + type: object + required: + - diskName + - diskURI + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the blob storage + type: string + fsType: + description: fsType is Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + azureFile: + description: azureFile represents an Azure File Service mount on the host and bind mount to the pod. + type: object + required: + - secretName + - shareName + properties: + readOnly: + description: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that contains Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + cephfs: + description: cephFS represents a Ceph FS mount on the host that shares a pod's lifetime + type: object + required: + - monitors + properties: + monitors: + description: 'monitors is Required: Monitors is a collection of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: array + items: + type: string + path: + description: 'path is Optional: Used as the mounted root, rather than the full Ceph tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + user: + description: 'user is optional: User is the rados user name, default is admin More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + cinder: + description: 'cinder represents a cinder volume attached and mounted on kubelets host machine. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: object + required: + - volumeID + properties: + fsType: + description: 'fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points to a secret object containing parameters used to connect to OpenStack.' + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + volumeID: + description: 'volumeID used to identify the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + configMap: + description: configMap represents a configMap that should populate this volume + type: object + properties: + defaultMode: + description: 'defaultMode is optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + items: + description: items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. + type: array + items: + description: Maps a string key to a path within a volume. + type: object + required: + - key + - path + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap or its keys must be defined + type: boolean + csi: + description: csi (Container Storage Interface) represents ephemeral storage that is handled by certain external CSI drivers (Beta feature). + type: object + required: + - driver + properties: + driver: + description: driver is the name of the CSI driver that handles this volume. Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", "xfs", "ntfs". If not provided, the empty value is passed to the associated CSI driver which will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference to the secret object containing sensitive information to pass to the CSI driver to complete the CSI NodePublishVolume and NodeUnpublishVolume calls. This field is optional, and may be empty if no secret is required. If the secret object contains more than one secret, all secret references are passed. + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + readOnly: + description: readOnly specifies a read-only configuration for the volume. Defaults to false (read/write). + type: boolean + volumeAttributes: + description: volumeAttributes stores driver-specific properties that are passed to the CSI driver. Consult your driver's documentation for supported values. + type: object + additionalProperties: + type: string + downwardAPI: + description: downwardAPI represents downward API about the pod that should populate this volume + type: object + properties: + defaultMode: + description: 'Optional: mode bits to use on created files by default. Must be a Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + items: + description: Items is a list of downward API volume file + type: array + items: + description: DownwardAPIVolumeFile represents information to create the file containing the pod field + type: object + required: + - path + properties: + fieldRef: + description: 'Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.' + type: object + required: + - fieldPath + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + mode: + description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: 'Required: Path is the relative path name of the file to be created. Must not be absolute or contain the ''..'' path. Must be utf-8 encoded. The first item of the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.' + type: object + required: + - resource + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + emptyDir: + description: 'emptyDir represents a temporary directory that shares a pod''s lifetime. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: object + properties: + medium: + description: 'medium represents what type of storage medium should back this directory. The default is "" which means to use the node''s default medium. Must be an empty string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + description: 'sizeLimit is the total amount of local storage required for this EmptyDir volume. The size limit is also applicable for memory medium. The maximum usage on memory medium EmptyDir would be the minimum value between the SizeLimit specified here and the sum of memory limits of all containers in a pod. The default is nil which means that the limit is undefined. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + ephemeral: + description: "ephemeral represents a volume that is handled by a cluster storage driver. The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, and deleted when the pod is removed. \n Use this if: a) the volume is only needed while the pod runs, b) features of normal volumes like restoring from snapshot or capacity tracking are needed, c) the storage driver is specified through a storage class, and d) the storage driver supports dynamic volume provisioning through a PersistentVolumeClaim (see EphemeralVolumeSource for more information on the connection between this volume type and PersistentVolumeClaim). \n Use PersistentVolumeClaim or one of the vendor-specific APIs for volumes that persist for longer than the lifecycle of an individual pod. \n Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to be used that way - see the documentation of the driver for more information. \n A pod can use both types of ephemeral volumes and persistent volumes at the same time." + type: object + properties: + volumeClaimTemplate: + description: "Will be used to create a stand-alone PVC to provision the volume. The pod in which this EphemeralVolumeSource is embedded will be the owner of the PVC, i.e. the PVC will be deleted together with the pod. The name of the PVC will be `-` where `` is the name from the `PodSpec.Volumes` array entry. Pod validation will reject the pod if the concatenated name is not valid for a PVC (for example, too long). \n An existing PVC with that name that is not owned by the pod will *not* be used for the pod to avoid using an unrelated volume by mistake. Starting the pod is then blocked until the unrelated PVC is removed. If such a pre-created PVC is meant to be used by the pod, the PVC has to updated with an owner reference to the pod once the pod exists. Normally this should not be necessary, but it may be useful when manually reconstructing a broken cluster. \n This field is read-only and no changes will be made by Kubernetes to the PVC after it has been created. \n Required, must not be nil." + type: object + required: + - spec + properties: + metadata: + description: May contain labels and annotations that will be copied into the PVC when creating it. No other fields are allowed and will be rejected during validation. + type: object + spec: + description: The specification for the PersistentVolumeClaim. The entire content is copied unchanged into the PVC that gets created from this template. The same fields as in a PersistentVolumeClaim are also valid here. + type: object + properties: + accessModes: + description: 'accessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + type: array + items: + type: string + dataSource: + description: 'dataSource field can be used to specify either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) * An existing PVC (PersistentVolumeClaim) If the provisioner or an external controller can support the specified data source, it will create a new volume based on the contents of the specified data source. When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. If the namespace is specified, then dataSourceRef will not be copied to dataSource.' + type: object + required: + - kind + - name + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + dataSourceRef: + description: 'dataSourceRef specifies the object from which to populate the volume with data, if a non-empty volume is desired. This may be any object from a non-empty API group (non core object) or a PersistentVolumeClaim object. When this field is specified, volume binding will only succeed if the type of the specified object matches some installed volume populator or dynamic provisioner. This field will replace the functionality of the dataSource field and as such if both fields are non-empty, they must have the same value. For backwards compatibility, when namespace isn''t specified in dataSourceRef, both fields (dataSource and dataSourceRef) will be set to the same value automatically if one of them is empty and the other is non-empty. When namespace is specified in dataSourceRef, dataSource isn''t set to the same value and must be empty. There are three important differences between dataSource and dataSourceRef: * While dataSource only allows two specific types of objects, dataSourceRef allows any non-core object, as well as PersistentVolumeClaim objects. * While dataSource ignores disallowed values (dropping them), dataSourceRef preserves all values, and generates an error if a disallowed value is specified. * While dataSource only allows local objects, dataSourceRef allows objects in any namespaces. (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled.' + type: object + required: + - kind + - name + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being referenced Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + resources: + description: 'resources represents the minimum resources the volume should have. If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements that are lower than previous value but must still be higher than capacity recorded in the status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + type: object + properties: + claims: + description: "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container. \n This is an alpha field and requires enabling the DynamicResourceAllocation feature gate. \n This field is immutable. It can only be set for containers." + type: array + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + type: object + required: + - name + properties: + name: + description: Name must match the name of one entry in pod.spec.resourceClaims of the Pod where this field is used. It makes that resource available inside a container. + type: string + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + description: 'Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + requests: + description: 'Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + additionalProperties: + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + selector: + description: selector is a label query over volumes to consider for binding. + type: object + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + type: array + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + type: object + required: + - key + - operator + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + type: array + items: + type: string + matchLabels: + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + additionalProperties: + type: string + storageClassName: + description: 'storageClassName is the name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference to the PersistentVolume backing this claim. + type: string + fc: + description: fc represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod. + type: object + properties: + fsType: + description: 'fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + lun: + description: 'lun is Optional: FC target lun number' + type: integer + format: int32 + readOnly: + description: 'readOnly is Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide names (WWNs)' + type: array + items: + type: string + wwids: + description: 'wwids Optional: FC volume world wide identifiers (wwids) Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously.' + type: array + items: + type: string + flexVolume: + description: flexVolume represents a generic volume resource that is provisioned/attached using an exec based plugin. + type: object + required: + - driver + properties: + driver: + description: driver is the name of the driver to use for this volume. + type: string + fsType: + description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + type: string + options: + description: 'options is Optional: this field holds extra command options if any.' + type: object + additionalProperties: + type: string + readOnly: + description: 'readOnly is Optional: defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.' + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + flocker: + description: flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running + type: object + properties: + datasetName: + description: datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. This is unique identifier of a Flocker dataset + type: string + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: object + required: + - pdName + properties: + fsType: + description: 'fsType is filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + partition: + description: 'partition is the partition in the volume that you want to mount. If omitted, the default is to mount by volume name. Examples: For volume /dev/sda1, you specify the partition as "1". Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: integer + format: int32 + pdName: + description: 'pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + gitRepo: + description: 'gitRepo represents a git repository at a particular revision. DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir into the Pod''s container.' + type: object + required: + - repository + properties: + directory: + description: directory is the target directory name. Must not contain or start with '..'. If '.' is supplied, the volume directory will be the git repository. Otherwise, if specified, the volume will contain the git repository in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified revision. + type: string + glusterfs: + description: 'glusterfs represents a Glusterfs mount on the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/glusterfs/README.md' + type: object + required: + - endpoints + - path + properties: + endpoints: + description: 'endpoints is the endpoint name that details Glusterfs topology. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the Glusterfs volume to be mounted with read-only permissions. Defaults to false. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + hostPath: + description: 'hostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath --- TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not mount host directories as read/write.' + type: object + required: + - path + properties: + path: + description: 'path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + iscsi: + description: 'iscsi represents an ISCSI Disk resource that is attached to a kubelet''s host machine and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + type: object + required: + - iqn + - lun + - targetPortal + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface Name that uses an iSCSI transport. Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + type: integer + format: int32 + portals: + description: portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). + type: array + items: + type: string + readOnly: + description: readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI target and initiator authentication + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + targetPortal: + description: targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260). + type: string + name: + description: 'name of the volume. Must be a DNS_LABEL and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the host that shares a pod''s lifetime More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: object + required: + - path + - server + properties: + path: + description: 'path that is exported by the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the NFS export to be mounted with read-only permissions. Defaults to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource represents a reference to a PersistentVolumeClaim in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: object + required: + - claimName + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly setting in VolumeMounts. Default false. + type: boolean + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine + type: object + required: + - pdID + properties: + fsType: + description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller persistent disk + type: string + portworxVolume: + description: portworxVolume represents a portworx volume attached and mounted on kubelets host machine + type: object + required: + - volumeID + properties: + fsType: + description: fSType represents the filesystem type to mount Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx volume + type: string + projected: + description: projected items for all in one resources secrets, configmaps, and downward API + type: object + properties: + defaultMode: + description: defaultMode are the mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set. + type: integer + format: int32 + sources: + description: sources is the list of volume projections + type: array + items: + description: Projection that may be projected along with other supported volume types + type: object + properties: + configMap: + description: configMap information about the configMap data to project + type: object + properties: + items: + description: items if unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. + type: array + items: + description: Maps a string key to a path within a volume. + type: object + required: + - key + - path + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether the ConfigMap or its keys must be defined + type: boolean + downwardAPI: + description: downwardAPI information about the downwardAPI data to project + type: object + properties: + items: + description: Items is a list of DownwardAPIVolume file + type: array + items: + description: DownwardAPIVolumeFile represents information to create the file containing the pod field + type: object + required: + - path + properties: + fieldRef: + description: 'Required: Selects a field of the pod: only annotations, labels, name and namespace are supported.' + type: object + required: + - fieldPath + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + mode: + description: 'Optional: mode bits used to set permissions on this file, must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: 'Required: Path is the relative path name of the file to be created. Must not be absolute or contain the ''..'' path. Must be utf-8 encoded. The first item of the relative path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported.' + type: object + required: + - resource + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + secret: + description: secret information about the secret data to project + type: object + properties: + items: + description: items if unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. + type: array + items: + description: Maps a string key to a path within a volume. + type: object + required: + - key + - path + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: optional field specify whether the Secret or its key must be defined + type: boolean + serviceAccountToken: + description: serviceAccountToken is information about the serviceAccountToken data to project + type: object + required: + - path + properties: + audience: + description: audience is the intended audience of the token. A recipient of a token must identify itself with an identifier specified in the audience of the token, and otherwise should reject the token. The audience defaults to the identifier of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is the requested duration of validity of the service account token. As the token approaches expiration, the kubelet volume plugin will proactively rotate the service account token. The kubelet will start trying to rotate the token if the token is older than 80 percent of its time to live or if the token is older than 24 hours.Defaults to 1 hour and must be at least 10 minutes. + type: integer + format: int64 + path: + description: path is the path relative to the mount point of the file to project the token into. + type: string + quobyte: + description: quobyte represents a Quobyte mount on the host that shares a pod's lifetime + type: object + required: + - registry + - volume + properties: + group: + description: group to map volume access to Default is no group + type: string + readOnly: + description: readOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte volume in the Backend Used with dynamically provisioned Quobyte volumes, value is set by the plugin + type: string + user: + description: user to map volume access to Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references an already created Quobyte volume by name. + type: string + rbd: + description: 'rbd represents a Rados Block Device mount on the host that shares a pod''s lifetime. More info: https://examples.k8s.io/volumes/rbd/README.md' + type: object + required: + - image + - monitors + properties: + fsType: + description: 'fsType is the filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd TODO: how do we prevent errors in the filesystem from compromising the machine' + type: string + image: + description: 'image is the rados image name. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring for RBDUser. Default is /etc/ceph/keyring. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: array + items: + type: string + pool: + description: 'pool is the rados pool name. Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication secret for RBDUser. If provided overrides keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + user: + description: 'user is the rados user name. Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + scaleIO: + description: scaleIO represents a ScaleIO persistent volume attached and mounted on Kubernetes nodes. + type: object + required: + - gateway + - secretRef + - system + properties: + fsType: + description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO Protection Domain for the configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret for ScaleIO user and other sensitive information. If this is not provided, Login operation will fail. + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication with Gateway, default false + type: boolean + storageMode: + description: storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume already created in the ScaleIO system that is associated with this volume source. + type: string + secret: + description: 'secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: object + properties: + defaultMode: + description: 'defaultMode is Optional: mode bits used to set permissions on created files by default. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. Defaults to 0644. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + items: + description: items If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'. + type: array + items: + description: Maps a string key to a path within a volume. + type: object + required: + - key + - path + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode bits used to set permissions on this file. Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. If not specified, the volume defaultMode will be used. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.' + type: integer + format: int32 + path: + description: path is the relative path of the file to map the key to. May not be an absolute path. May not contain the path element '..'. May not start with the string '..'. + type: string + optional: + description: optional field specify whether the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the secret in the pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + storageos: + description: storageOS represents a StorageOS volume attached and mounted on Kubernetes nodes. + type: object + properties: + fsType: + description: fsType is the filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret to use for obtaining the StorageOS API credentials. If not specified, default values will be attempted. + type: object + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + volumeName: + description: volumeName is the human-readable name of the StorageOS volume. Volume names are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the scope of the volume within StorageOS. If no namespace is specified then the Pod's namespace will be used. This allows the Kubernetes name scoping to be mirrored within StorageOS for tighter integration. Set VolumeName to any name to override the default behaviour. Set to "default" if you are not using namespaces within StorageOS. Namespaces that do not pre-exist within StorageOS will be created. + type: string + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached and mounted on kubelets host machine + type: object + required: + - volumePath + properties: + fsType: + description: fsType is filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies vSphere volume vmdk + type: string + installPlanApproval: + description: Approval is the user approval policy for an InstallPlan. It must be one of "Automatic" or "Manual". + type: string + name: + type: string + source: + type: string + sourceNamespace: + type: string + startingCSV: + type: string + status: + type: object + required: + - lastUpdated + properties: + catalogHealth: + description: CatalogHealth contains the Subscription's view of its relevant CatalogSources' status. It is used to determine SubscriptionStatusConditions related to CatalogSources. + type: array + items: + description: SubscriptionCatalogHealth describes the health of a CatalogSource the Subscription knows about. + type: object + required: + - catalogSourceRef + - healthy + - lastUpdated + properties: + catalogSourceRef: + description: CatalogSourceRef is a reference to a CatalogSource. + type: object + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + healthy: + description: Healthy is true if the CatalogSource is healthy; false otherwise. + type: boolean + lastUpdated: + description: LastUpdated represents the last time that the CatalogSourceHealth changed + type: string + format: date-time + conditions: + description: Conditions is a list of the latest available observations about a Subscription's current state. + type: array + items: + description: SubscriptionCondition represents the latest available observations of a Subscription's state. + type: object + required: + - status + - type + properties: + lastHeartbeatTime: + description: LastHeartbeatTime is the last time we got an update on a given condition + type: string + format: date-time + lastTransitionTime: + description: LastTransitionTime is the last time the condition transit from one status to another + type: string + format: date-time + message: + description: Message is a human-readable message indicating details about last transition. + type: string + reason: + description: Reason is a one-word CamelCase reason for the condition's last transition. + type: string + status: + description: Status is the status of the condition, one of True, False, Unknown. + type: string + type: + description: Type is the type of Subscription condition. + type: string + currentCSV: + description: CurrentCSV is the CSV the Subscription is progressing to. + type: string + installPlanGeneration: + description: InstallPlanGeneration is the current generation of the installplan + type: integer + installPlanRef: + description: InstallPlanRef is a reference to the latest InstallPlan that contains the Subscription's current CSV. + type: object + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: "spec.containers{name}" (where "name" refers to the name of the container that triggered the event) or if no container name is specified "spec.containers[2]" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object. TODO: this design is not final and this field is subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + installedCSV: + description: InstalledCSV is the CSV currently installed by the Subscription. + type: string + installplan: + description: 'Install is a reference to the latest InstallPlan generated for the Subscription. DEPRECATED: InstallPlanRef' + type: object + required: + - apiVersion + - kind + - name + - uuid + properties: + apiVersion: + type: string + kind: + type: string + name: + type: string + uuid: + description: UID is a type that holds unique ID values, including UUIDs. Because we don't ONLY use UUIDs, this is an alias to string. Being a type captures intent and helps make sure that UIDs and names do not get conflated. + type: string + lastUpdated: + description: LastUpdated represents the last time that the Subscription status was updated. + type: string + format: date-time + reason: + description: Reason is the reason the Subscription was transitioned to its current state. + type: string + state: + description: State represents the current state of the Subscription + type: string + served: true + storage: true + subresources: + status: {} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/crds/vizier_crd.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/crds/vizier_crd.yaml new file mode 100644 index 000000000..b25d7b592 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/crds/vizier_crd.yaml @@ -0,0 +1,347 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.4.1 + creationTimestamp: null + name: viziers.px.dev +spec: + group: px.dev + names: + kind: Vizier + listKind: VizierList + plural: viziers + singular: vizier + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Vizier is the Schema for the viziers API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VizierSpec defines the desired state of Vizier + properties: + autopilot: + description: Autopilot should be set if running Pixie on GKE Autopilot. + type: boolean + clockConverter: + description: ClockConverter specifies which routine to use for converting + timestamps to a synced reference time. + enum: + - default + - grpc + type: string + cloudAddr: + description: CloudAddr is the address of the cloud instance that the + Vizier should be pointing to. + type: string + clusterName: + description: ClusterName is a name for the Vizier instance, usually + specifying which cluster the Vizier is deployed to. If not specified, + a random name will be generated. + type: string + customDeployKeySecret: + description: CustomDeployKeySecret is the name of the secret where + the deploy key is stored. + type: string + dataAccess: + description: DataAccess defines the level of data that may be accesssed + when executing a script on the cluster. If none specified, assumes + full data access. + enum: + - Full + - Restricted + type: string + dataCollectorParams: + description: DataCollectorParams specifies the set of params for configuring + the dataCollector. If no params are specified, defaults are used. + properties: + customPEMFlags: + additionalProperties: + type: string + description: This contains custom flags that should be passed + to the PEM via environment variables. + type: object + datastreamBufferSize: + description: DatastreamBufferSize is the data buffer size per + connection. Default size is 1 Mbyte. For high-throughput applications, + try increasing this number if experiencing data loss. + format: int32 + type: integer + datastreamBufferSpikeSize: + description: DatastreamBufferSpikeSize is the maximum temporary + size of a data stream buffer before processing. + format: int32 + type: integer + type: object + deployKey: + description: DeployKey is the deploy key associated with the Vizier + instance. This is used to link the Vizier to a specific user/org. + This is required unless specifying a CustomDeployKeySecret. + type: string + devCloudNamespace: + description: 'DevCloudNamespace should be specified only for dev versions + of Pixie cloud which have no ingress to help redirect traffic to + the correct service. The DevCloudNamespace is the namespace that + the dev Pixie cloud is running on, for example: "plc-dev".' + type: string + disableAutoUpdate: + description: DisableAutoUpdate specifies whether auto update should + be enabled for the Vizier instance. + type: boolean + leadershipElectionParams: + description: LeadershipElectionParams specifies configurable values + for the K8s leaderships elections which Vizier uses manage pod leadership. + properties: + electionPeriodMs: + description: ElectionPeriodMs defines how frequently Vizier attempts + to run a K8s leader election, in milliseconds. The period also + determines how long Vizier waits for a leader election response + back from the K8s API. If the K8s API is slow to respond, consider + increasing this number. + format: int64 + type: integer + type: object + patches: + additionalProperties: + type: string + description: Patches defines patches that should be applied to Vizier + resources. The key of the patch should be the name of the resource + that is patched. The value of the patch is the patch, encoded as + a string which follow the "strategic merge patch" rules for K8s. + type: object + pemMemoryLimit: + description: PemMemoryLimit is a memory limit applied specifically + to PEM pods. + type: string + pemMemoryRequest: + description: PemMemoryRequest is a memory request applied specifically + to PEM pods. It will automatically use the value of pemMemoryLimit + if not specified. + type: string + pod: + description: Pod defines the policy for creating Vizier pods. + properties: + annotations: + additionalProperties: + type: string + description: Annotations specifies the annotations to attach to + pods the operator creates. + type: object + labels: + additionalProperties: + type: string + description: Labels specifies the labels to attach to pods the + operator creates. + type: object + nodeSelector: + additionalProperties: + type: string + description: 'NodeSelector is a selector which must be true for + the pod to fit on a node. Selector which must match a node''s + labels for the pod to be scheduled on that node. More info: + https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + This field cannot be updated once the cluster is created.' + type: object + resources: + description: Resources is the resource requirements for a container. + This field cannot be updated once the cluster is created. + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry in + pod.spec.resourceClaims of the Pod where this field + is used. It makes that resource available inside a + container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum amount of compute + resources required. If Requests is omitted for a container, + it defaults to Limits if that is explicitly specified, otherwise + to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: The securityContext which should be set on non-privileged + pods. All pods which require privileged permissions will still + require a privileged securityContext. + properties: + enabled: + description: Whether a securityContext should be set on the + pod. In cases where no PSPs are applied to the cluster, + this is not necessary. + type: boolean + fsGroup: + description: A special supplemental group that applies to + all containers in a pod. + format: int64 + type: integer + runAsGroup: + description: The GID to run the entrypoint of the container + process. + format: int64 + type: integer + runAsUser: + description: The UID to run the entrypoint of the container + process. + format: int64 + type: integer + type: object + tolerations: + description: 'Tolerations allows scheduling pods on nodes with + matching taints. More info: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/: + This field cannot be updated once the cluster is created.' + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, allowed + values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies + to. Empty means match all taint keys. If the key is empty, + operator must be Exists; this combination means to match + all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to + the value. Valid operators are Exists and Equal. Defaults + to Equal. Exists is equivalent to wildcard for value, + so that a pod can tolerate all taints of a particular + category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the taint + forever (do not evict). Zero and negative values will + be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + type: object + registry: + description: 'Registry specifies the image registry to use rather + than Pixie''s default registry (gcr.io). We expect any forward slashes + in Pixie''s image paths are replaced with a "-". For example: "gcr.io/pixie-oss/pixie-dev/vizier/metadata_server_image:latest" + should be pushed to "$registry/gcr.io-pixie-oss-pixie-dev-vizier-metadata_server_image:latest".' + type: string + useEtcdOperator: + description: UseEtcdOperator specifies whether the metadata service + should use etcd for storage. + type: boolean + version: + description: Version is the desired version of the Vizier instance. + type: string + type: object + status: + description: VizierStatus defines the observed state of Vizier + properties: + checksum: + description: A checksum of the last reconciled Vizier spec. If this + checksum does not match the checksum of the current vizier spec, + reconciliation should be performed. + format: byte + type: string + lastReconciliationPhaseTime: + description: LastReconciliationPhaseTime is the last time that the + ReconciliationPhase changed. + format: date-time + type: string + message: + description: Message is a human-readable message with details about + why the Vizier is in this condition. + type: string + operatorVersion: + description: OperatorVersion is the actual version of the Operator + instance. + type: string + reconciliationPhase: + description: ReconciliationPhase describes the state the Reconciler + is in for this Vizier. See the documentation above the ReconciliationPhase + type for more information. + type: string + sentryDSN: + description: SentryDSN is key for Viziers that is used to send errors + and stacktraces to Sentry. + type: string + version: + description: Version is the actual version of the Vizier instance. + type: string + vizierPhase: + description: VizierPhase is a high-level summary of where the Vizier + is in its lifecycle. + type: string + vizierReason: + description: VizierReason is a short, machine understandable string + that gives the reason for the transition into the Vizier's current + status. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/00_olm.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/00_olm.yaml new file mode 100644 index 000000000..fe058140f --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/00_olm.yaml @@ -0,0 +1,232 @@ +{{- $olmCRDFound := false }} +{{- $nsLookup := len (lookup "v1" "Namespace" "" "") }} +{{- range $index, $crdLookup := (lookup "apiextensions.k8s.io/v1" "CustomResourceDefinition" "" "").items -}}{{ if eq $crdLookup.metadata.name "operators.operators.coreos.com"}}{{ $olmCRDFound = true }}{{ end }}{{end}} +{{ if and (not $olmCRDFound) (not (eq $nsLookup 0))}}{{ fail "CRDs missing! Please deploy CRDs from https://github.com/pixie-io/pixie/tree/main/k8s/operator/helm/crds to continue with deploy." }}{{end}} +{{- $lookupLen := 0 -}}{{- $opLookup := (lookup "operators.coreos.com/v1" "OperatorGroup" "" "").items -}}{{if $opLookup }}{{ $lookupLen = len $opLookup }}{{ end }} +{{ if (or (eq (.Values.deployOLM | toString) "true") (and (not (eq (.Values.deployOLM | toString) "false")) (eq $lookupLen 0))) }} +{{ if not (eq .Values.olmNamespace .Release.Namespace) }} +--- +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.olmNamespace }} +{{ end }} +--- +kind: ServiceAccount +apiVersion: v1 +metadata: + name: olm-operator-serviceaccount + namespace: {{ .Values.olmNamespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: system:controller:operator-lifecycle-manager +rules: +- apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] +- nonResourceURLs: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: olm-operator-cluster-binding-olm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:controller:operator-lifecycle-manager +subjects: +- kind: ServiceAccount + name: olm-operator-serviceaccount + namespace: {{ .Values.olmNamespace }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: olm-operator + namespace: {{ .Values.olmNamespace }} + labels: + app: olm-operator +spec: + strategy: + type: RollingUpdate + replicas: 1 + selector: + matchLabels: + app: olm-operator + template: + metadata: + labels: + app: olm-operator + spec: + serviceAccountName: olm-operator-serviceaccount + containers: + - name: olm-operator + command: + - /bin/olm + args: + - --namespace + - $(OPERATOR_NAMESPACE) + - --writeStatusName + - "" + image: {{ if .Values.registry }}{{ .Values.registry }}/quay.io-operator-framework-{{ else }}quay.io/operator-framework/{{ end }}olm@sha256:1b6002156f568d722c29138575733591037c24b4bfabc67946f268ce4752c3e6 + ports: + - containerPort: 8080 + - containerPort: 8081 + name: metrics + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: 8080 + readinessProbe: + httpGet: + path: /healthz + port: 8080 + terminationMessagePolicy: FallbackToLogsOnError + env: + - name: OPERATOR_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: OPERATOR_NAME + value: olm-operator + resources: + requests: + cpu: 10m + memory: 160Mi + nodeSelector: + kubernetes.io/os: linux + tolerations: + - key: "kubernetes.io/arch" + operator: "Equal" + value: "amd64" + effect: "NoSchedule" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "amd64" + effect: "NoExecute" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "arm64" + effect: "NoSchedule" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "arm64" + effect: "NoExecute" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: catalog-operator + namespace: {{ .Values.olmNamespace }} + labels: + app: catalog-operator +spec: + strategy: + type: RollingUpdate + replicas: 1 + selector: + matchLabels: + app: catalog-operator + template: + metadata: + labels: + app: catalog-operator + spec: + serviceAccountName: olm-operator-serviceaccount + containers: + - name: catalog-operator + command: + - /bin/catalog + args: + - '--namespace' + - {{ .Values.olmNamespace }} + - --configmapServerImage={{ if .Values.registry }}{{ .Values.registry }}/quay.io-operator-framework-{{ else }}quay.io/operator-framework/{{ end }}configmap-operator-registry:latest + - --util-image + - {{ if .Values.registry }}{{ .Values.registry }}/quay.io-operator-framework-{{ else }}quay.io/operator-framework/{{ end }}olm@sha256:1b6002156f568d722c29138575733591037c24b4bfabc67946f268ce4752c3e6 + - --opmImage + - {{ if .Values.registry }}{{ .Values.registry }}/quay.io-operator-framework-{{ else }}quay.io/operator-framework/{{ end }}opm@sha256:d999588bd4e9509ec9e75e49adfb6582d256e9421e454c7fb5e9fe57e7b1aada + image: {{ if .Values.registry }}{{ .Values.registry }}/quay.io-operator-framework-{{ else }}quay.io/operator-framework/{{ end }}olm@sha256:1b6002156f568d722c29138575733591037c24b4bfabc67946f268ce4752c3e6 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + - containerPort: 8081 + name: metrics + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: 8080 + readinessProbe: + httpGet: + path: /healthz + port: 8080 + terminationMessagePolicy: FallbackToLogsOnError + env: + resources: + requests: + cpu: 10m + memory: 80Mi + nodeSelector: + kubernetes.io/os: linux + tolerations: + - key: "kubernetes.io/arch" + operator: "Equal" + value: "amd64" + effect: "NoSchedule" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "amd64" + effect: "NoExecute" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "arm64" + effect: "NoSchedule" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "arm64" + effect: "NoExecute" +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-olm-edit + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: ["operators.coreos.com"] + resources: ["subscriptions"] + verbs: ["create", "update", "patch", "delete"] +- apiGroups: ["operators.coreos.com"] + resources: ["clusterserviceversions", "catalogsources", "installplans", "subscriptions"] + verbs: ["delete"] +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: aggregate-olm-view + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-view: "true" +rules: +- apiGroups: ["operators.coreos.com"] + resources: ["clusterserviceversions", "catalogsources", "installplans", "subscriptions", "operatorgroups"] + verbs: ["get", "list", "watch"] +- apiGroups: ["packages.operators.coreos.com"] + resources: ["packagemanifests", "packagemanifests/icon"] + verbs: ["get", "list", "watch"] +--- +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: olm-operators + namespace: {{ .Values.olmNamespace }} +spec: + targetNamespaces: + - {{ .Values.olmNamespace }} +{{- end}} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/01_px_olm.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/01_px_olm.yaml new file mode 100644 index 000000000..2c2921958 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/01_px_olm.yaml @@ -0,0 +1,13 @@ +{{ if not (eq .Values.olmOperatorNamespace .Release.Namespace) }} +--- +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.olmOperatorNamespace }} +{{ end }} +--- +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: global-operators + namespace: {{ .Values.olmOperatorNamespace }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/02_catalog.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/02_catalog.yaml new file mode 100644 index 000000000..e7f68804a --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/02_catalog.yaml @@ -0,0 +1,37 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: CatalogSource +metadata: + name: pixie-operator-index + namespace: {{ .Values.olmOperatorNamespace }} + {{- if .Values.olmCatalogSource.annotations }} + annotations: {{ .Values.olmCatalogSource.annotations | toYaml | nindent 4 }} + {{- end }} + {{- if .Values.olmCatalogSource.labels }} + labels: {{ .Values.olmCatalogSource.labels | toYaml | nindent 4 }} + {{- end }} +spec: + sourceType: grpc + image: {{ if .Values.registry }}{{ .Values.registry }}/gcr.io-pixie-oss-pixie-prod-operator-bundle_index:0.0.1{{ else }}gcr.io/pixie-oss/pixie-prod/operator/bundle_index:0.0.1{{ end }} + displayName: Pixie Vizier Operator + publisher: px.dev + updateStrategy: + registryPoll: + interval: 10m + grpcPodConfig: + tolerations: + - key: "kubernetes.io/arch" + operator: "Equal" + value: "amd64" + effect: "NoSchedule" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "amd64" + effect: "NoExecute" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "arm64" + effect: "NoSchedule" + - key: "kubernetes.io/arch" + operator: "Equal" + value: "arm64" + effect: "NoExecute" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/03_subscription.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/03_subscription.yaml new file mode 100644 index 000000000..78223cc9e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/03_subscription.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: pixie-operator-subscription + namespace: {{ .Values.olmOperatorNamespace }} +spec: + channel: {{ .Values.olmBundleChannel }} + name: pixie-operator + source: pixie-operator-index + sourceNamespace: {{ .Values.olmOperatorNamespace }} + installPlanApproval: Automatic diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/04_vizier.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/04_vizier.yaml new file mode 100644 index 000000000..7c8ca65ad --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/04_vizier.yaml @@ -0,0 +1,100 @@ +apiVersion: px.dev/v1alpha1 +kind: Vizier +metadata: + name: {{ .Values.name }} + namespace: {{ .Release.Namespace }} +spec: + {{- if .Values.version }} + version: {{ .Values.version }} + {{- end }} + {{- if .Values.deployKey }} + deployKey: {{ .Values.deployKey }} + {{- end }} + {{- if .Values.customDeployKeySecret }} + customDeployKeySecret: {{ .Values.customDeployKeySecret }} + {{- end }} + cloudAddr: {{ .Values.cloudAddr }} + disableAutoUpdate: {{ .Values.disableAutoUpdate }} + useEtcdOperator: {{ .Values.useEtcdOperator }} + {{- if (.Values.global).cluster }} + clusterName: {{ .Values.global.cluster }} + {{- else if .Values.clusterName }} + clusterName: {{ .Values.clusterName }} + {{- end }} + {{- if .Values.devCloudNamespace }} + devCloudNamespace: {{ .Values.devCloudNamespace }} + {{- end }} + {{- if .Values.pemMemoryLimit }} + pemMemoryLimit: {{ .Values.pemMemoryLimit }} + {{- end }} + {{- if .Values.pemMemoryRequest }} + pemMemoryRequest: {{ .Values.pemMemoryRequest }} + {{- end }} + {{- if .Values.dataAccess }} + dataAccess: {{ .Values.dataAccess }} + {{- end }} + {{- if .Values.patches }} + patches: {{ .Values.patches | toYaml | nindent 4 }} + {{- end }} + {{- if ((.Values.global).images).registry }} + registry: {{ .Values.global.images.registry }} + {{- else if .Values.registry }} + registry: {{ .Values.registry }} + {{- end}} + {{- if .Values.autopilot }} + autopilot: {{ .Values.autopilot }} + {{- end}} + {{- if .Values.dataCollectorParams }} + dataCollectorParams: + {{- if .Values.dataCollectorParams.datastreamBufferSize }} + datastreamBufferSize: {{ .Values.dataCollectorParams.datastreamBufferSize }} + {{- end }} + {{- if .Values.dataCollectorParams.datastreamBufferSpikeSize }} + datastreamBufferSpikeSize: {{ .Values.dataCollectorParams.datastreamBufferSpikeSize }} + {{- end }} + {{- if .Values.dataCollectorParams.customPEMFlags }} + customPEMFlags: + {{- range $key, $value := .Values.dataCollectorParams.customPEMFlags}} + {{$key}}: "{{$value}}" + {{- end}} + {{- end }} + {{- end}} + {{- if .Values.leadershipElectionParams }} + leadershipElectionParams: + {{- if .Values.leadershipElectionParams.electionPeriodMs }} + electionPeriodMs: {{ .Values.leadershipElectionParams.electionPeriodMs }} + {{- end }} + {{- end }} + {{- if or .Values.pod.securityContext (or .Values.pod.nodeSelector (or .Values.pod.tolerations (or .Values.pod.annotations (or .Values.pod.labels .Values.pod.resources)))) }} + pod: + {{- if .Values.pod.annotations }} + annotations: {{ .Values.pod.annotations | toYaml | nindent 6 }} + {{- end }} + {{- if .Values.pod.labels }} + labels: {{ .Values.pod.labels | toYaml | nindent 6 }} + {{- end }} + {{- if .Values.pod.resources }} + resources: {{ .Values.pod.resources | toYaml | nindent 6 }} + {{- end }} + {{- if .Values.pod.nodeSelector }} + nodeSelector: {{ .Values.pod.nodeSelector | toYaml | nindent 6 }} + {{- end }} + {{- if .Values.pod.tolerations }} + tolerations: {{ .Values.pod.tolerations | toYaml | nindent 4 }} + {{- end }} + {{- if .Values.pod.securityContext }} + securityContext: + enabled: {{ .Values.pod.securityContext.enabled }} + {{- if .Values.pod.securityContext.enabled }} + {{- if .Values.pod.securityContext.fsGroup }} + fsGroup: {{ .Values.pod.securityContext.fsGroup }} + {{- end }} + {{- if .Values.pod.securityContext.runAsUser }} + runAsUser: {{ .Values.pod.securityContext.runAsUser }} + {{- end }} + {{- if .Values.pod.securityContext.runAsGroup }} + runAsGroup: {{ .Values.pod.securityContext.runAsGroup }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/deleter.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/deleter.yaml new file mode 100644 index 000000000..b1cde0c92 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/deleter.yaml @@ -0,0 +1,25 @@ +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + helm.sh/hook: pre-delete + helm.sh/hook-delete-policy: hook-succeeded + name: vizier-deleter + namespace: '{{ .Release.Namespace }}' +spec: + template: + metadata: + name: vizier-deleter + spec: + containers: + - env: + - name: PL_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: PL_VIZIER_NAME + value: '{{ .Values.name }}' + image: gcr.io/pixie-oss/pixie-prod/operator-vizier_deleter:0.1.6 + name: delete-job + restartPolicy: Never + serviceAccountName: pl-deleter-service-account diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/deleter_role.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/deleter_role.yaml new file mode 100644 index 000000000..73e5ec7e4 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/templates/deleter_role.yaml @@ -0,0 +1,77 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: pl-deleter-service-account +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: pl-deleter-cluster-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: pl-deleter-role +subjects: +- kind: ServiceAccount + name: pl-deleter-service-account + namespace: "{{ .Release.Namespace }}" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: pl-deleter-cluster-role +rules: +# Allow actions on Kubernetes objects +- apiGroups: + - rbac.authorization.k8s.io + - etcd.database.coreos.com + - nats.io + resources: + - clusterroles + - clusterrolebindings + - persistentvolumes + - etcdclusters + - natsclusters + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: pl-deleter-role +rules: +- apiGroups: + - "" + - apps + - rbac.authorization.k8s.io + - extensions + - batch + - policy + resources: + - configmaps + - secrets + - pods + - services + - deployments + - daemonsets + - persistentvolumes + - roles + - rolebindings + - serviceaccounts + - statefulsets + - cronjobs + - jobs + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: pl-deleter-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: pl-deleter-role +subjects: +- kind: ServiceAccount + name: pl-deleter-service-account + namespace: "{{ .Release.Namespace }}" diff --git a/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/values.yaml b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/values.yaml new file mode 100644 index 000000000..a3ffe7c9d --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/charts/pixie-operator-chart/values.yaml @@ -0,0 +1,75 @@ +## OLM configuration +# OLM is used for deploying and ensuring the operator is up-to-date. +# deployOLM indicates whether OLM should be deployed. This should only be +# disabled if an instance of OLM is already configured on the cluster. +# Should be string "true" if true, but "false" otherwise. If empty, defaults +# to whether OLM is present in the cluster. +deployOLM: "" +# The namespace that olm should run in. If olm has already been deployed +# to the cluster, this should be the namespace that olm is already running in. +olmNamespace: "olm" +# The namespace which olm operators should run in. If olm has already +# been deployed to the cluster, this should be the namespace that the olm operators +# are running in. +olmOperatorNamespace: "px-operator" +# The bundle channel which OLM should listen to for the Vizier operator bundles. +# Should be "stable" for production-versions of the operator, and "test" for release candidates. +olmBundleChannel: "stable" +# Optional annotations and labels for CatalogSource. +olmCatalogSource: + # Optional custom annotations to add to deployed pods managed by CatalogSource object. + annotations: {} + # Optional custom labels to add to deployed pods managed by CatalogSource object. + labels: {} +## Vizier configuration +# The name of the Vizier instance deployed to the cluster. +name: "pixie" +# The name of the cluster that the Vizier is monitoring. If empty, +# a random name will be generated. +clusterName: "" +# The version of the Vizier instance deployed to the cluster. If empty, +# the operator will automatically deploy the latest version. +version: "" +# The deploy key is used to link the deployed Vizier to a specific user/project. +# This is required if not specifying a customDeployKeySecret, and can be generated through the UI or CLI. +deployKey: "" +# The deploy key may be read from a custom secret in the Pixie namespace. This secret should be formatted where the +# key of the deploy key is "deploy-key". +customDeployKeySecret: "" +# Whether auto-update should be disabled. +disableAutoUpdate: false +# Whether the metadata service should use etcd for in-memory storage. Recommended +# only for clusters which do not have persistent volumes configured. +useEtcdOperator: false +# The address of the Pixie cloud instance that the Vizier should be connected to. +# This should only be updated when using a self-hosted version of Pixie Cloud. +cloudAddr: "withpixie.ai:443" +# DevCloudNamespace should be specified only for self-hosted versions of Pixie cloud which have no ingress to help +# redirect traffic to the correct service. The DevCloudNamespace is the namespace that the dev Pixie cloud is +# running on, for example: "plc-dev". +devCloudNamespace: "" +# A memory limit applied specifically to PEM pods. If none is specified, a default limit of 2Gi is set. +pemMemoryLimit: "" +# A memory request applied specifically to PEM pods. If none is specified, it will default to pemMemoryLimit. +pemMemoryRequest: "" +# DataAccess defines the level of data that may be accesssed when executing a script on the cluster. +dataAccess: "Full" +pod: + # Optional custom annotations to add to deployed pods. + annotations: {} + # Optional custom labels to add to deployed pods. + labels: {} + resources: {} + # limits: + # cpu: 500m + # memory: 7Gi + # requests: + # cpu: 100m + # memory: 5Gi + nodeSelector: {} + tolerations: [] +# A set of custom patches to apply to the deployed Vizier resources. +# The key should be the name of the resource to apply the patch to, and the value is the patch to apply. +# Currently, only a JSON format is accepted, such as: +# `{"spec": {"template": {"spec": { "tolerations": [{"key": "test", "operator": "Exists", "effect": "NoExecute" }]}}}}` +patches: {} diff --git a/charts/new-relic/nri-bundle/5.0.87/ci/test-values.yaml b/charts/new-relic/nri-bundle/5.0.87/ci/test-values.yaml new file mode 100644 index 000000000..7ba6c8c32 --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/ci/test-values.yaml @@ -0,0 +1,21 @@ +global: + licenseKey: 1234567890abcdef1234567890abcdef12345678 + cluster: test-cluster + +infrastructure: + enabled: true + +prometheus: + enabled: true + +webhook: + enabled: true + +ksm: + enabled: true + +kubeEvents: + enabled: true + +logging: + enabled: true diff --git a/charts/new-relic/nri-bundle/5.0.87/questions.yaml b/charts/new-relic/nri-bundle/5.0.87/questions.yaml new file mode 100644 index 000000000..de3fa9fea --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/questions.yaml @@ -0,0 +1,113 @@ +questions: +- variable: infrastructure.enabled + default: true + required: false + type: boolean + label: Enable Infrastructure + group: "Select Components" +- variable: prometheus.enabled + default: false + required: false + type: boolean + label: Enable Prometheus + group: "Select Components" +- variable: ksm.enabled + default: false + required: false + type: boolean + label: Enable KSM + group: "Select Components" + description: "This is mandatory if `Enable Infrastructure` is set to `true` and the user does not provide its own instance of KSM version >=1.8 and <=2.0" +- variable: webhook.enabled + default: true + required: false + type: boolean + label: Enable webhook + group: "Select Components" +- variable: kubeEvents.enabled + default: false + required: false + type: boolean + label: Enable Kube Events + group: "Select Components" +- variable: logging.enabled + default: false + required: false + type: boolean + label: Enable Logging + group: "Select Components" +- variable: newrelic-pixie.enabled + default: false + required: false + type: boolean + label: Enable New Relic Pixie Integration + group: "Select Components" + show_subquestion_if: true + subquestions: + - variable: newrelic-pixie.apiKey + default: "" + required: false + type: string + label: New Relic Pixie API Key + group: "Select Components" + description: "Required if deploying Pixie." +- variable: pixie-chart.enabled + default: false + required: false + type: boolean + label: Enable Pixie Chart + group: "Select Components" + show_subquestion_if: true + subquestions: + - variable: pixie-chart.deployKey + default: "" + required: false + type: string + label: Pixie Deploy Key + group: "Select Components" + description: "Required if deploying Pixie." + - variable: pixie-chart.clusterName + default: "" + required: false + type: string + label: Kubernetes Cluster Name for Pixie + group: "Select Components" + description: "Required if deploying Pixie." +- variable: newrelic-infra-operator.enabled + default: false + required: false + type: boolean + label: Enable New Relic Infra Operator + group: "Select Components" +- variable: metrics-adapter.enabled + default: false + required: false + type: boolean + label: Enable Metrics Adapter + group: "Select Components" +- variable: global.licenseKey + default: "xxxx" + required: true + type: string + label: New Relic License Key + group: "Global Settings" +- variable: global.cluster + default: "xxxx" + required: true + type: string + label: Name of Kubernetes Cluster for New Relic + group: "Global Settings" +- variable: global.lowDataMode + default: false + required: false + type: boolean + label: Enable Low Data Mode + description: "Reduces amount of data ingest by New Relic." + group: "Global Settings" +- variable: global.privileged + default: false + required: false + type: boolean + label: Enable Privileged Mode + description: "Allows for access to underlying node from container." + group: "Global Settings" diff --git a/charts/new-relic/nri-bundle/5.0.87/values.yaml b/charts/new-relic/nri-bundle/5.0.87/values.yaml new file mode 100644 index 000000000..47c58df8e --- /dev/null +++ b/charts/new-relic/nri-bundle/5.0.87/values.yaml @@ -0,0 +1,169 @@ +newrelic-infrastructure: + # newrelic-infrastructure.enabled -- Install the [`newrelic-infrastructure` chart](https://github.com/newrelic/nri-kubernetes/tree/main/charts/newrelic-infrastructure) + enabled: true + +nri-prometheus: + # nri-prometheus.enabled -- Install the [`nri-prometheus` chart](https://github.com/newrelic/nri-prometheus/tree/main/charts/nri-prometheus) + enabled: false + +nri-metadata-injection: + # nri-metadata-injection.enabled -- Install the [`nri-metadata-injection` chart](https://github.com/newrelic/k8s-metadata-injection/tree/main/charts/nri-metadata-injection) + enabled: true + +kube-state-metrics: + # kube-state-metrics.enabled -- Install the [`kube-state-metrics` chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics) from the stable helm charts repository. + # This is mandatory if `infrastructure.enabled` is set to `true` and the user does not provide its own instance of KSM version >=1.8 and <=2.0. Note, kube-state-metrics v2+ disables labels/annotations + # metrics by default. You can enable the target labels/annotations metrics to be monitored by using the metricLabelsAllowlist/metricAnnotationsAllowList options described [here](https://github.com/prometheus-community/helm-charts/blob/159cd8e4fb89b8b107dcc100287504bb91bf30e0/charts/kube-state-metrics/values.yaml#L274) in + # your Kubernetes clusters. + enabled: false + +nri-kube-events: + # nri-kube-events.enabled -- Install the [`nri-kube-events` chart](https://github.com/newrelic/nri-kube-events/tree/main/charts/nri-kube-events) + enabled: false + +newrelic-logging: + # newrelic-logging.enabled -- Install the [`newrelic-logging` chart](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging) + enabled: false + +newrelic-pixie: + # newrelic-pixie.enabled -- Install the [`newrelic-pixie`](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-pixie) + enabled: false + +k8s-agents-operator: + # k8s-agents-operator.enabled -- Install the [`k8s-agents-operator` chart](https://github.com/newrelic/k8s-agents-operator/tree/main/charts/k8s-agents-operator) + enabled: false + +pixie-chart: + # pixie-chart.enabled -- Install the [`pixie-chart` chart](https://docs.pixielabs.ai/installing-pixie/install-schemes/helm/#3.-deploy) + enabled: false + +newrelic-infra-operator: + # newrelic-infra-operator.enabled -- Install the [`newrelic-infra-operator` chart](https://github.com/newrelic/newrelic-infra-operator/tree/main/charts/newrelic-infra-operator) (Beta) + enabled: false + +newrelic-prometheus-agent: + # newrelic-prometheus-agent.enabled -- Install the [`newrelic-prometheus-agent` chart](https://github.com/newrelic/newrelic-prometheus-configurator/tree/main/charts/newrelic-prometheus-agent) + enabled: false + +newrelic-k8s-metrics-adapter: + # newrelic-k8s-metrics-adapter.enabled -- Install the [`newrelic-k8s-metrics-adapter.` chart](https://github.com/newrelic/newrelic-k8s-metrics-adapter/tree/main/charts/newrelic-k8s-metrics-adapter) (Beta) + enabled: false + + +# -- change the behaviour globally to all the supported helm charts. +# See [user's guide of the common library](https://github.com/newrelic/helm-charts/blob/master/library/common-library/README.md) for further information. +# @default -- See [`values.yaml`](values.yaml) +global: + # -- The cluster name for the Kubernetes cluster. + cluster: "" + + # -- The license key for your New Relic Account. This will be preferred configuration option if both `licenseKey` and `customSecret` are specified. + licenseKey: "" + # -- The license key for your New Relic Account. This will be preferred configuration option if both `insightsKey` and `customSecret` are specified. + insightsKey: "" + # -- Name of the Secret object where the license key is stored + customSecretName: "" + # -- Key in the Secret object where the license key is stored + customSecretLicenseKey: "" + + # -- Additional labels for chart objects + labels: {} + # -- Additional labels for chart pods + podLabels: {} + + images: + # -- Changes the registry where to get the images. Useful when there is an internal image cache/proxy + registry: "" + # -- Set secrets to be able to fetch images + pullSecrets: [] + + serviceAccount: + # -- Add these annotations to the service account we create + annotations: {} + # -- Configures if the service account should be created or not + create: + # -- Change the name of the service account. This is honored if you disable on this chart the creation of the service account so you can use your own + name: + + # -- (bool) Sets pod's hostNetwork + # @default -- false + hostNetwork: + # -- Sets pod's dnsConfig + dnsConfig: {} + + # -- Sets pod's priorityClassName + priorityClassName: "" + # -- Sets security context (at pod level) + podSecurityContext: {} + # -- Sets security context (at container level) + containerSecurityContext: {} + + # -- Sets pod/node affinities + affinity: {} + # -- Sets pod's node selector + nodeSelector: {} + # -- Sets pod's tolerations to node taints + tolerations: [] + + # -- Adds extra attributes to the cluster and all the metrics emitted to the backend + customAttributes: {} + + # -- (bool) Reduces number of metrics sent in order to reduce costs + # @default -- false + lowDataMode: + + # -- (bool) In each integration it has different behavior. See [Further information](#values-managed-globally-3) but all aims to send less metrics to the backend to try to save costs | + # @default -- false + privileged: + + # -- (bool) Must be set to `true` when deploying in an EKS Fargate environment + # @default -- false + fargate: + + # -- Configures the integration to send all HTTP/HTTPS request through the proxy in that URL. The URL should have a standard format like `https://user:password@hostname:port` + proxy: "" + + # -- (bool) Send the metrics to the staging backend. Requires a valid staging license key + # @default -- false + nrStaging: + fedramp: + # fedramp.enabled -- (bool) Enables FedRAMP + # @default -- false + enabled: + + # -- (bool) Sets the debug logs to this integration or all integrations if it is set globally + # @default -- false + verboseLog: + + +# To add values to the subcharts. Follow Helm's guide: https://helm.sh/docs/chart_template_guide/subcharts_and_globals + +# If you wish to monitor services running on Kubernetes you can provide integrations +# configuration under `integrations_config` that it will passed down to the `newrelic-infrastructure` chart. +# +# You just need to create a new entry where the "name" is the filename of the configuration file and the data is the content of +# the integration configuration. The name must end in ".yaml" as this will be the +# filename generated and the Infrastructure agent only looks for YAML files. +# +# The data part is the actual integration configuration as described in the spec here: +# https://docs.newrelic.com/docs/integrations/integrations-sdk/file-specifications/integration-configuration-file-specifications-agent-v180 +# +# In the following example you can see how to monitor a Redis integration with autodiscovery +# +# +# newrelic-infrastructure: +# integrations: +# nri-redis-sampleapp: +# discovery: +# command: +# exec: /var/db/newrelic-infra/nri-discovery-kubernetes --tls --port 10250 +# match: +# label.app: sampleapp +# integrations: +# - name: nri-redis +# env: +# # using the discovered IP as the hostname address +# HOSTNAME: ${discovery.ip} +# PORT: 6379 +# labels: +# env: test diff --git a/charts/percona/psmdb-db/1.16.3/.helmignore b/charts/percona/psmdb-db/1.16.3/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/charts/percona/psmdb-db/1.16.3/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/percona/psmdb-db/1.16.3/Chart.yaml b/charts/percona/psmdb-db/1.16.3/Chart.yaml new file mode 100644 index 000000000..5b85549a1 --- /dev/null +++ b/charts/percona/psmdb-db/1.16.3/Chart.yaml @@ -0,0 +1,19 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Percona Server for MongoDB + catalog.cattle.io/kube-version: '>=1.21-0' + catalog.cattle.io/release-name: psmdb-db +apiVersion: v2 +appVersion: 1.16.2 +description: A Helm chart for installing Percona Server MongoDB Cluster Databases + using the PSMDB Operator. +home: https://www.percona.com/doc/kubernetes-operator-for-psmongodb/index.html +icon: file://assets/icons/psmdb-db.png +kubeVersion: '>=1.21-0' +maintainers: +- email: tomislav.plavcic@percona.com + name: tplavcic +- email: natalia.marukovich@percona.com + name: nmarukovich +name: psmdb-db +version: 1.16.3 diff --git a/charts/percona/psmdb-db/1.16.3/README.md b/charts/percona/psmdb-db/1.16.3/README.md new file mode 100644 index 000000000..952e529ae --- /dev/null +++ b/charts/percona/psmdb-db/1.16.3/README.md @@ -0,0 +1,267 @@ +# Percona Server for MongoDB + +This chart deploys Percona Server for MongoDB Cluster on Kubernetes controlled by Percona Operator for MongoDB. + +Useful links: +- [Operator Github repository](https://github.com/percona/percona-server-mongodb-operator) +- [Operator Documentation](https://www.percona.com/doc/kubernetes-operator-for-psmongodb/index.html) + +## Pre-requisites +* Percona Operator for MongoDB running in your Kubernetes cluster. See installation details [here](https://github.com/percona/percona-helm-charts/blob/main/charts/psmdb-operator) or in the [Operator Documentation](https://www.percona.com/doc/kubernetes-operator-for-psmongodb/helm.html). +* Kubernetes 1.26+ +* Helm v3 + +# Chart Details +This chart will deploy Percona Server for MongoDB Cluster in Kubernetes. It will create a Custom Resource, and the Operator will trigger the creation of corresponding Kubernetes primitives: StatefulSets, Pods, Secrets, etc. + +## Installing the Chart +To install the chart with the `psmdb` release name using a dedicated namespace (recommended): + +```sh +helm repo add percona https://percona.github.io/percona-helm-charts/ +helm install my-db percona/psmdb-db --version 1.16.2 --namespace my-namespace +``` + +The chart can be customized using the following configurable parameters: + +| Parameter | Description | Default | +| ------------------------------- | ------------------------------------------------------------------------------|---------------------------------------| +| `crVersion` | CR Cluster Manifest version | `1.16.2` | +| `pause` | Stop PSMDB Database safely | `false` | +| `unmanaged` | Start cluster and don't manage it (cross cluster replication) | `false` | +| `unsafeFlags.tls` | Allows users from configuring a cluster without TLS/SSL certificates | `false` | +| `unsafeFlags.replsetSize` | Allows users from configuring a cluster with unsafe parameters: starting it with less than 3 replica set instances or with an even number of replica set instances without additional arbiter | `false` | +| `unsafeFlags.mongosSize` | Allows users from configuring a sharded cluster with less than 3 config server Pods or less than 2 mongos Pods | `false` | +| `unsafeFlags.terminationGracePeriod` | Allows users from configuring a sharded cluster without termination grace period for replica set | `false` | +| `unsafeFlags.backupIfUnhealthy` | Allows running backup on a cluster with failed health checks | `false` | +| `clusterServiceDNSSuffix` | The (non-standard) cluster domain to be used as a suffix of the Service name | `""` | +| `clusterServiceDNSMode` | Mode for the cluster service dns (Internal/ServiceMesh) | `""` | +| `annotations` | PSMDB custom resource annotations | `{}` | +| `ignoreAnnotations` | The list of annotations to be ignored by the Operator | `[]` | +| `ignoreLabels` | The list of labels to be ignored by the Operator | `[]` | +| `multiCluster.enabled` | Enable Multi Cluster Services (MCS) cluster mode | `false` | +| `multiCluster.DNSSuffix` | The cluster domain to be used as a suffix for multi-cluster Services used by Kubernetes | `""` | +| `updateStrategy` | Regulates the way how PSMDB Cluster Pods will be updated after setting a new image | `SmartUpdate` | +| `upgradeOptions.versionServiceEndpoint` | Endpoint for actual PSMDB Versions provider | `https://check.percona.com/versions/` | +| `upgradeOptions.apply` | PSMDB image to apply from version service - recommended, latest, actual version like 4.4.2-4 | `disabled` | +| `upgradeOptions.schedule` | Cron formatted time to execute the update | `"0 2 * * *"` | +| `upgradeOptions.setFCV` | Set feature compatibility version on major upgrade | `false` | +| `finalizers:delete-psmdb-pvc` | Set this if you want to delete database persistent volumes on cluster deletion | `[]` | +| `finalizers:delete-psmdb-pods-in-order` | Set this if you want to delete PSMDB pods in order (primary last) | `[]` | +| `image.repository` | PSMDB Container image repository | `percona/percona-server-mongodb` | +| `image.tag` | PSMDB Container image tag | `6.0.9-7` | +| `imagePullPolicy` | The policy used to update images | `Always` | +| `imagePullSecrets` | PSMDB Container pull secret | `[]` | +| `initImage.repository` | Repository for custom init image | `""` | +| `initImage.tag` | Tag for custom init image | `""` | +| `initContainerSecurityContext` | A custom Kubernetes Security Context for a Container for the initImage | `{}` | +| `tls.mode` | Control usage of TLS (allowTLS, preferTLS, requireTLS, disabled) | `preferTLS` | +| `tls.certValidityDuration` | The validity duration of the external certificate for cert manager | `""` | +| `tls.allowInvalidCertificates` | If enabled the mongo shell will not attempt to validate the server certificates | `true` | +| `tls.issuerConf.name` | A cert-manager issuer name | `""` | +| `tls.issuerConf.kind` | A cert-manager issuer kind | `""` | +| `tls.issuerConf.group` | A cert-manager issuer group | `""` | +| `secrets.users` | The name of the Secrets object for the MongoDB users required to run the operator | `""` | +| `secrets.encryptionKey` | Set secret for data at rest encryption key | `""` | +| `secrets.vault` | Specifies a secret object to provide integration with HashiCorp Vault | `""` | +| `secrets.ldapSecret` | Specifies a secret object for LDAP over TLS connection between MongoDB and OpenLDAP server | `""` | +| `secrets.sse` | The name of the Secrets object for server side encryption credentials | `""` | +| `secrets.ssl` | A secret with TLS certificate generated for external communications | `""` | +| `secrets.sslInternal` | A secret with TLS certificate generated for internal communications | `""` | +| `pmm.enabled` | Enable integration with [Percona Monitoring and Management software](https://www.percona.com/blog/2020/07/23/using-percona-kubernetes-operators-with-percona-monitoring-and-management/) | `false` | +| `pmm.image.repository` | PMM Container image repository | `percona/pmm-client` | +| `pmm.image.tag` | PMM Container image tag | `2.41.2` | +| `pmm.serverHost` | PMM server related K8S service hostname | `monitoring-service` | +|| +| `replsets.rs0.name` | ReplicaSet name | `rs0` | +| `replsets.rs0.size` | ReplicaSet size (pod quantity) | `3` | +| `replsets.rs0.terminationGracePeriodSeconds` | The amount of seconds Kubernetes will wait for a clean replica set Pods termination | `""` | +| `replsets.rs0.externalNodes` | ReplicaSet external nodes (cross cluster replication) | `[]` | +| `replsets.rs0.configuration` | Custom config for mongod in replica set | `""` | +| `replsets.rs0.topologySpreadConstraints` | Control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains | `{}` | +| `replsets.rs0.serviceAccountName` | Run replicaset Containers under specified K8S SA | `""` | +| `replsets.rs0.affinity.antiAffinityTopologyKey` | ReplicaSet Pod affinity | `kubernetes.io/hostname` | +| `replsets.rs0.affinity.advanced` | ReplicaSet Pod advanced affinity | `{}` | +| `replsets.rs0.tolerations` | ReplicaSet Pod tolerations | `[]` | +| `replsets.rs0.priorityClass` | ReplicaSet Pod priorityClassName | `""` | +| `replsets.rs0.annotations` | ReplicaSet Pod annotations | `{}` | +| `replsets.rs0.labels` | ReplicaSet Pod labels | `{}` | +| `replsets.rs0.nodeSelector` | ReplicaSet Pod nodeSelector labels | `{}` | +| `replsets.rs0.livenessProbe` | ReplicaSet Pod livenessProbe structure | `{}` | +| `replsets.rs0.readinessProbe` | ReplicaSet Pod readinessProbe structure | `{}` | +| `replsets.rs0.storage` | Set cacheSizeRatio or other custom MongoDB storage options | `{}` | +| `replsets.rs0.podSecurityContext` | Set the security context for a Pod | `{}` | +| `replsets.rs0.containerSecurityContext` | Set the security context for a Container | `{}` | +| `replsets.rs0.runtimeClass` | ReplicaSet Pod runtimeClassName | `""` | +| `replsets.rs0.sidecars` | ReplicaSet Pod sidecars | `{}` | +| `replsets.rs0.sidecarVolumes` | ReplicaSet Pod sidecar volumes | `[]` | +| `replsets.rs0.sidecarPVCs` | ReplicaSet Pod sidecar PVCs | `[]` | +| `replsets.rs0.podDisruptionBudget.maxUnavailable` | ReplicaSet failed Pods maximum quantity | `1` | +| `replsets.rs0.splitHorizons` | External URI for Split-horizon for replica set Pods of the exposed cluster | `{}` | +| `replsets.rs0.expose.enabled` | Allow access to replicaSet from outside of Kubernetes | `false` | +| `replsets.rs0.expose.exposeType` | Network service access point type | `ClusterIP` | +| `replsets.rs0.expose.loadBalancerSourceRanges` | Limit client IP's access to Load Balancer | `{}` | +| `replsets.rs0.expose.serviceAnnotations` | ReplicaSet service annotations | `{}` | +| `replsets.rs0.expose.serviceLabels` | ReplicaSet service labels | `{}` | +| `replsets.rs0.schedulerName` | ReplicaSet Pod schedulerName | `""` | +| `replsets.rs0.resources` | ReplicaSet Pods resource requests and limits | `{}` | +| `replsets.rs0.volumeSpec` | ReplicaSet Pods storage resources | `{}` | +| `replsets.rs0.volumeSpec.emptyDir` | ReplicaSet Pods emptyDir K8S storage | `{}` | +| `replsets.rs0.volumeSpec.hostPath` | ReplicaSet Pods hostPath K8S storage | | +| `replsets.rs0.volumeSpec.hostPath.path` | ReplicaSet Pods hostPath K8S storage path | `""` | +| `replsets.rs0.volumeSpec.hostPath.type` | Type for hostPath volume | `Directory` | +| `replsets.rs0.volumeSpec.pvc` | ReplicaSet Pods PVC request parameters | | +| `replsets.rs0.volumeSpec.pvc.annotations` | The Kubernetes annotations metadata for Persistent Volume Claim | `{}` | +| `replsets.rs0.volumeSpec.pvc.labels` | The Kubernetes labels metadata for Persistent Volume Claim | `{}` | +| `replsets.rs0.volumeSpec.pvc.storageClassName` | ReplicaSet Pods PVC target storageClass | `""` | +| `replsets.rs0.volumeSpec.pvc.accessModes` | ReplicaSet Pods PVC access policy | `[]` | +| `replsets.rs0.volumeSpec.pvc.resources.requests.storage` | ReplicaSet Pods PVC storage size | `3Gi` | +| `replsets.rs0.hostAliases` | The IP address for Kubernetes host aliases | `[]` | +| `replsets.rs0.nonvoting.enabled` | Add MongoDB nonvoting Pods | `false` | +| `replsets.rs0.nonvoting.podSecurityContext` | Set the security context for a Pod | `{}` | +| `replsets.rs0.nonvoting.containerSecurityContext` | Set the security context for a Container | `{}` | +| `replsets.rs0.nonvoting.size` | Number of nonvoting Pods | `1` | +| `replsets.rs0.nonvoting.configuration` | Custom config for mongod nonvoting member | `""` | +| `replsets.rs0.nonvoting.serviceAccountName` | Run replicaset nonvoting Container under specified K8S SA | `""` | +| `replsets.rs0.nonvoting.affinity.antiAffinityTopologyKey` | Nonvoting Pods affinity | `kubernetes.io/hostname` | +| `replsets.rs0.nonvoting.affinity.advanced` | Nonvoting Pods advanced affinity | `{}` | +| `replsets.rs0.nonvoting.tolerations` | Nonvoting Pod tolerations | `[]` | +| `replsets.rs0.nonvoting.priorityClass` | Nonvoting Pod priorityClassName | `""` | +| `replsets.rs0.nonvoting.annotations` | Nonvoting Pod annotations | `{}` | +| `replsets.rs0.nonvoting.labels` | Nonvoting Pod labels | `{}` | +| `replsets.rs0.nonvoting.nodeSelector` | Nonvoting Pod nodeSelector labels | `{}` | +| `replsets.rs0.nonvoting.podDisruptionBudget.maxUnavailable` | Nonvoting failed Pods maximum quantity | `1` | +| `replsets.rs0.nonvoting.resources` | Nonvoting Pods resource requests and limits | `{}` | +| `replsets.rs0.nonvoting.volumeSpec` | Nonvoting Pods storage resources | `{}` | +| `replsets.rs0.nonvoting.volumeSpec.emptyDir` | Nonvoting Pods emptyDir K8S storage | `{}` | +| `replsets.rs0.nonvoting.volumeSpec.hostPath` | Nonvoting Pods hostPath K8S storage | | +| `replsets.rs0.nonvoting.volumeSpec.hostPath.path` | Nonvoting Pods hostPath K8S storage path | `""` | +| `replsets.rs0.nonvoting.volumeSpec.hostPath.type` | Type for hostPath volume | `Directory` | +| `replsets.rs0.nonvoting.volumeSpec.pvc` | Nonvoting Pods PVC request parameters | | +| `replsets.rs0.nonvoting.volumeSpec.pvc.annotations` | The Kubernetes annotations metadata for Persistent Volume Claim | `{}` | +| `replsets.rs0.nonvoting.volumeSpec.pvc.labels` | The Kubernetes labels metadata for Persistent Volume Claim | `{}` | +| `replsets.rs0.nonvoting.volumeSpec.pvc.storageClassName` | Nonvoting Pods PVC target storageClass | `""` | +| `replsets.rs0.nonvoting.volumeSpec.pvc.accessModes` | Nonvoting Pods PVC access policy | `[]` | +| `replsets.rs0.nonvoting.volumeSpec.pvc.resources.requests.storage` | Nonvoting Pods PVC storage size | `3Gi` | +| `replsets.rs0.arbiter.enabled` | Create MongoDB arbiter service | `false` | +| `replsets.rs0.arbiter.size` | MongoDB arbiter Pod quantity | `1` | +| `replsets.rs0.arbiter.serviceAccountName` | Run replicaset arbiter Container under specified K8S SA | `""` | +| `replsets.rs0.arbiter.affinity.antiAffinityTopologyKey` | MongoDB arbiter Pod affinity | `kubernetes.io/hostname` | +| `replsets.rs0.arbiter.affinity.advanced` | MongoDB arbiter Pod advanced affinity | `{}` | +| `replsets.rs0.arbiter.tolerations` | MongoDB arbiter Pod tolerations | `[]` | +| `replsets.rs0.arbiter.priorityClass` | MongoDB arbiter priorityClassName | `""` | +| `replsets.rs0.arbiter.annotations` | MongoDB arbiter Pod annotations | `{}` | +| `replsets.rs0.arbiter.labels` | MongoDB arbiter Pod labels | `{}` | +| `replsets.rs0.arbiter.nodeSelector` | MongoDB arbiter Pod nodeSelector labels | `{}` | +| | +| `sharding.enabled` | Enable sharding setup | `true` | +| `sharding.balancer.enabled` | Enable/disable balancer | `true` | +| `sharding.configrs.size` | Config ReplicaSet size (pod quantity) | `3` | +| `sharding.configrs.terminationGracePeriodSeconds` | The amount of seconds Kubernetes will wait for a clean replica set Pods termination | `""` | +| `sharding.configrs.externalNodes` | Config ReplicaSet external nodes (cross cluster replication) | `[]` | +| `sharding.configrs.configuration` | Custom config for mongod in config replica set | `""` | +| `sharding.configrs.topologySpreadConstraints` | Control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains | `{}` | +| `sharding.configrs.serviceAccountName` | Run sharding configrs Containers under specified K8S SA | `""` | +| `sharding.configrs.affinity.antiAffinityTopologyKey` | Config ReplicaSet Pod affinity | `kubernetes.io/hostname` | +| `sharding.configrs.affinity.advanced` | Config ReplicaSet Pod advanced affinity | `{}` | +| `sharding.configrs.tolerations` | Config ReplicaSet Pod tolerations | `[]` | +| `sharding.configrs.priorityClass` | Config ReplicaSet Pod priorityClassName | `""` | +| `sharding.configrs.annotations` | Config ReplicaSet Pod annotations | `{}` | +| `sharding.configrs.labels` | Config ReplicaSet Pod labels | `{}` | +| `sharding.configrs.nodeSelector` | Config ReplicaSet Pod nodeSelector labels | `{}` | +| `sharding.configrs.livenessProbe` | Config ReplicaSet Pod livenessProbe structure | `{}` | +| `sharding.configrs.readinessProbe` | Config ReplicaSet Pod readinessProbe structure | `{}` | +| `sharding.configrs.storage` | Set cacheSizeRatio or other custom MongoDB storage options | `{}` | +| `sharding.configrs.podSecurityContext` | Set the security context for a Pod | `{}` | +| `sharding.configrs.containerSecurityContext` | Set the security context for a Container | `{}` | +| `sharding.configrs.runtimeClass` | Config ReplicaSet Pod runtimeClassName | `""` | +| `sharding.configrs.sidecars` | Config ReplicaSet Pod sidecars | `{}` | +| `sharding.configrs.sidecarVolumes` | Config ReplicaSet Pod sidecar volumes | `[]` | +| `sharding.configrs.sidecarPVCs` | Config ReplicaSet Pod sidecar PVCs | `[]` | +| `sharding.configrs.podDisruptionBudget.maxUnavailable` | Config ReplicaSet failed Pods maximum quantity | `1` | +| `sharding.configrs.expose.enabled` | Allow access to cfg replica from outside of Kubernetes | `false` | +| `sharding.configrs.expose.exposeType` | Network service access point type | `ClusterIP` | +| `sharding.configrs.expose.loadBalancerSourceRanges` | Limit client IP's access to Load Balancer | `{}` | +| `sharding.configrs.expose.serviceAnnotations` | Config ReplicaSet service annotations | `{}` | +| `sharding.configrs.expose.serviceLabels` | Config ReplicaSet service labels | `{}` | +| `sharding.configrs.resources.limits.cpu` | Config ReplicaSet resource limits CPU | `300m` | +| `sharding.configrs.resources.limits.memory` | Config ReplicaSet resource limits memory | `0.5G` | +| `sharding.configrs.resources.requests.cpu` | Config ReplicaSet resource requests CPU | `300m` | +| `sharding.configrs.resources.requests.memory` | Config ReplicaSet resource requests memory | `0.5G` | +| `sharding.configrs.volumeSpec.hostPath` | Config ReplicaSet hostPath K8S storage | | +| `sharding.configrs.volumeSpec.hostPath.path` | Config ReplicaSet hostPath K8S storage path | `""` | +| `sharding.configrs.volumeSpec.hostPath.type` | Type for hostPath volum | `Directory` | +| `sharding.configrs.volumeSpec.emptyDir` | Config ReplicaSet Pods emptyDir K8S storage | | +| `sharding.configrs.volumeSpec.pvc` | Config ReplicaSet Pods PVC request parameters | | +| `sharding.configrs.volumeSpec.pvc.annotations` | The Kubernetes annotations metadata for Persistent Volume Claim | `{}` | +| `sharding.configrs.volumeSpec.pvc.labels` | The Kubernetes labels metadata for Persistent Volume Claim | `{}` | +| `sharding.configrs.volumeSpec.pvc.storageClassName` | Config ReplicaSet Pods PVC storageClass | `""` | +| `sharding.configrs.volumeSpec.pvc.accessModes` | Config ReplicaSet Pods PVC access policy | `[]` | +| `sharding.configrs.volumeSpec.pvc.resources.requests.storage` | Config ReplicaSet Pods PVC storage size | `3Gi` | +| `sharding.configrs.hostAliases` | The IP address for Kubernetes host aliases | `[]` | +| `sharding.mongos.size` | Mongos size (pod quantity) | `3` | +| `sharding.mongos.terminationGracePeriodSeconds` | The amount of seconds Kubernetes will wait for a clean mongos Pods termination | `""` | +| `sharding.mongos.configuration` | Custom config for mongos | `""` | +| `sharding.mongos.topologySpreadConstraints` | Control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains | `{}` | +| `sharding.mongos.serviceAccountName` | Run sharding mongos Containers under specified K8S SA | `""` | +| `sharding.mongos.affinity.antiAffinityTopologyKey` | Mongos Pods affinity | `kubernetes.io/hostname` | +| `sharding.mongos.affinity.advanced` | Mongos Pods advanced affinity | `{}` | +| `sharding.mongos.tolerations` | Mongos Pods tolerations | `[]` | +| `sharding.mongos.priorityClass` | Mongos Pods priorityClassName | `""` | +| `sharding.mongos.annotations` | Mongos Pods annotations | `{}` | +| `sharding.mongos.labels` | Mongos Pods labels | `{}` | +| `sharding.mongos.nodeSelector` | Mongos Pods nodeSelector labels | `{}` | +| `sharding.mongos.livenessProbe` | Mongos Pod livenessProbe structure | `{}` | +| `sharding.mongos.readinessProbe` | Mongos Pod readinessProbe structure | `{}` | +| `sharding.mongos.podSecurityContext` | Set the security context for a Pod | `{}` | +| `sharding.mongos.containerSecurityContext` | Set the security context for a Container | `{}` | +| `sharding.mongos.runtimeClass` | Mongos Pod runtimeClassName | `""` | +| `sharding.mongos.sidecars` | Mongos Pod sidecars | `{}` | +| `sharding.mongos.sidecarVolumes` | Mongos Pod sidecar volumes | `[]` | +| `sharding.mongos.sidecarPVCs` | Mongos Pod sidecar PVCs | `[]` | +| `sharding.mongos.podDisruptionBudget.maxUnavailable` | Mongos failed Pods maximum quantity | `1` | +| `sharding.mongos.resources.limits.cpu` | Mongos Pods resource limits CPU | `300m` | +| `sharding.mongos.resources.limits.memory` | Mongos Pods resource limits memory | `0.5G` | +| `sharding.mongos.resources.requests.cpu` | Mongos Pods resource requests CPU | `300m` | +| `sharding.mongos.resources.requests.memory` | Mongos Pods resource requests memory | `0.5G` | +| `sharding.mongos.expose.exposeType` | Mongos service exposeType | `ClusterIP` | +| `sharding.mongos.expose.servicePerPod` | Create a separate ClusterIP Service for each mongos instance | `false` | +| `sharding.mongos.expose.loadBalancerSourceRanges` | Limit client IP's access to Load Balancer | `{}` | +| `sharding.mongos.expose.serviceAnnotations` | Mongos service annotations | `{}` | +| `sharding.mongos.expose.serviceLabels` | Mongos service labels | `{}` | +| `sharding.mongos.expose.nodePort` | Custom port if exposing mongos via NodePort | `""` | +| `sharding.mongos.hostAliases` | The IP address for Kubernetes host aliases | `[]` | +| | +| `backup.enabled` | Enable backup PBM agent | `true` | +| `backup.annotations` | Backup job annotations | `{}` | +| `backup.podSecurityContext` | Set the security context for a Pod | `{}` | +| `backup.containerSecurityContext` | Set the security context for a Container | `{}` | +| `backup.restartOnFailure` | Backup Pods restart policy | `true` | +| `backup.image.repository` | PBM Container image repository | `percona/percona-backup-mongodb` | +| `backup.image.tag` | PBM Container image tag | `2.3.0` | +| `backup.storages` | Local/remote backup storages settings | `{}` | +| `backup.pitr.enabled` | Enable point in time recovery for backup | `false` | +| `backup.pitr.oplogOnly` | Start collecting oplogs even if full logical backup doesn't exist | `false` | +| `backup.pitr.oplogSpanMin` | Number of minutes between the uploads of oplogs | `10` | +| `backup.pitr.compressionType` | The point-in-time-recovery chunks compression format | `""` | +| `backup.pitr.compressionLevel` | The point-in-time-recovery chunks compression level | `""` | +| `backup.configuration.backupOptions` | Custom configuration settings for backup | `{}` | +| `backup.configuration.restoreOptions` | Custom configuration settings for restore | `{}` | +| `backup.tasks` | Backup working schedule | `{}` | +| `users` | PSMDB essential users | `{}` | + + +Specify parameters using `--set key=value[,key=value]` argument to `helm install` +Notice that you can use multiple replica sets only with sharding enabled. + +## Examples + +### Deploy a replica set with disabled backups and no mongos pods + +This is great for a dev PSMDB/MongoDB cluster as it doesn't bother with backups and sharding setup. + +```bash +$ helm install dev --namespace psmdb . \ + --set runUid=1001 --set "replsets.rs0.volumeSpec.pvc.resources.requests.storage=20Gi" \ + --set backup.enabled=false --set sharding.enabled=false +``` diff --git a/charts/percona/psmdb-db/1.16.3/templates/NOTES.txt b/charts/percona/psmdb-db/1.16.3/templates/NOTES.txt new file mode 100644 index 000000000..3f294ce22 --- /dev/null +++ b/charts/percona/psmdb-db/1.16.3/templates/NOTES.txt @@ -0,0 +1,40 @@ +# + + % _____ + %%% | __ \ + ###%%%%%%%%%%%%* | |__) |__ _ __ ___ ___ _ __ __ _ + ### ##%% %%%% | ___/ _ \ '__/ __/ _ \| '_ \ / _` | + #### ##% %%%% | | | __/ | | (_| (_) | | | | (_| | + ### #### %%% |_| \___|_| \___\___/|_| |_|\__,_| + ,((### ### %%% _ _ _____ _ + (((( (### #### %%%% | | / _ \ / ____| | | + ((( ((# ###### | | _| (_) |___ | (___ __ _ _ _ __ _ __| | + (((( (((# #### | |/ /> _ >> https://percona.com/k8s <<< + +Percona Server for MongoDB cluster is deployed now. Get the username and password: + + ADMIN_USER=$(kubectl -n {{ .Release.Namespace }} get secrets {{ include "psmdb-database.fullname" . }}-secrets -o jsonpath="{.data.MONGODB_USER_ADMIN_USER}" | base64 --decode) + ADMIN_PASSWORD=$(kubectl -n {{ .Release.Namespace }} get secrets {{ include "psmdb-database.fullname" . }}-secrets -o jsonpath="{.data.MONGODB_USER_ADMIN_PASSWORD}" | base64 --decode) + +Connect to the cluster: +{{- if .Values.sharding.enabled }} + + kubectl run -i --rm --tty percona-client --image=percona/percona-server-mongodb:7.0 --restart=Never \ + -- mongosh "mongodb://${ADMIN_USER}:${ADMIN_PASSWORD}@{{ include "psmdb-database.fullname" . }}-mongos.{{ .Release.Namespace }}.svc.cluster.local/admin?ssl=false" + +{{- else }} + + kubectl run -i --rm --tty percona-client --image=percona/percona-server-mongodb:7.0 --restart=Never \ + -- mongosh "mongodb+srv://${ADMIN_USER}:${ADMIN_PASSWORD}@{{ include "psmdb-database.fullname" . }}-{{ .Values.replsets.rs0.name }}.{{ .Release.Namespace }}.svc.cluster.local/admin?replicaSet=rs0&ssl=false" + +{{- end }} + diff --git a/charts/percona/psmdb-db/1.16.3/templates/_helpers.tpl b/charts/percona/psmdb-db/1.16.3/templates/_helpers.tpl new file mode 100644 index 000000000..47b33a5a7 --- /dev/null +++ b/charts/percona/psmdb-db/1.16.3/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "psmdb-database.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 "psmdb-database.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 21 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 21 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 21 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "psmdb-database.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 21 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "psmdb-database.labels" -}} +app.kubernetes.io/name: {{ include "psmdb-database.name" . }} +helm.sh/chart: {{ include "psmdb-database.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} diff --git a/charts/percona/psmdb-db/1.16.3/templates/cluster-secret.yaml b/charts/percona/psmdb-db/1.16.3/templates/cluster-secret.yaml new file mode 100644 index 000000000..c2019b278 --- /dev/null +++ b/charts/percona/psmdb-db/1.16.3/templates/cluster-secret.yaml @@ -0,0 +1,12 @@ +{{- if hasKey .Values "users" }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "psmdb-database.fullname" . }}-secrets + namespace: {{ .Release.Namespace }} + labels: +{{ include "psmdb-database.labels" . | indent 4 }} +type: Opaque +stringData: +{{ .Values.users | toYaml | indent 2 }} +{{- end -}} diff --git a/charts/percona/psmdb-db/1.16.3/templates/cluster.yaml b/charts/percona/psmdb-db/1.16.3/templates/cluster.yaml new file mode 100644 index 000000000..db93beb0d --- /dev/null +++ b/charts/percona/psmdb-db/1.16.3/templates/cluster.yaml @@ -0,0 +1,615 @@ +apiVersion: psmdb.percona.com/v1 +kind: PerconaServerMongoDB +metadata: + {{- if .Values.annotations }} + annotations: +{{ .Values.annotations | toYaml | indent 4 }} + {{- end }} + name: {{ include "psmdb-database.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: +{{ include "psmdb-database.labels" . | indent 4 }} + finalizers: +{{ .Values.finalizers | toYaml | indent 4 }} +spec: + crVersion: {{ .Values.crVersion }} + pause: {{ .Values.pause }} + unmanaged: {{ .Values.unmanaged }} + {{- if .Values.platform }} + platform: {{ .Values.platform }} + {{- end }} + {{- if .Values.clusterServiceDNSSuffix }} + clusterServiceDNSSuffix: {{ .Values.clusterServiceDNSSuffix }} + {{- end }} + {{- if .Values.clusterServiceDNSMode }} + clusterServiceDNSMode: {{ .Values.clusterServiceDNSMode }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.imagePullPolicy }}" + {{- if .Values.unsafeFlags }} + unsafeFlags: +{{ .Values.unsafeFlags | toYaml | indent 4 }} + {{- end }} + {{- if .Values.ignoreAnnotations }} + ignoreAnnotations: +{{ .Values.ignoreAnnotations | toYaml | indent 4 }} + {{- end }} + {{- if .Values.ignoreLabels }} + ignoreLabels: +{{ .Values.ignoreLabels | toYaml | indent 4 }} + {{- end }} + multiCluster: + enabled: {{ .Values.multiCluster.enabled }} + {{- if .Values.multiCluster.DNSSuffix }} + DNSSuffix: {{ .Values.multiCluster.DNSSuffix }} + {{- end }} + {{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ .Values.imagePullSecrets | toYaml | indent 4 }} + {{- end }} + {{- if .Values.initImage }} + initImage: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" + {{- end }} + {{- if .Values.initContainerSecurityContext }} + initContainerSecurityContext: +{{ .Values.initContainerSecurityContext | toYaml | indent 4 }} + {{- end }} + {{- if .Values.tls }} + tls: +{{ .Values.tls | toYaml | indent 4 }} + {{- end }} + {{- if .Values.secrets }} + secrets: +{{ .Values.secrets | toYaml | indent 4 }} + {{- else }} + secrets: + users: {{ include "psmdb-database.fullname" . }}-secrets + {{- end }} + {{- if .Values.updateStrategy }} + updateStrategy: {{ .Values.updateStrategy }} + upgradeOptions: + versionServiceEndpoint: {{ .Values.upgradeOptions.versionServiceEndpoint }} + apply: {{ .Values.upgradeOptions.apply }} + schedule: {{ .Values.upgradeOptions.schedule }} + setFCV: {{ .Values.upgradeOptions.setFCV }} + {{- end }} + pmm: + enabled: {{ .Values.pmm.enabled }} + image: "{{ .Values.pmm.image.repository }}:{{ .Values.pmm.image.tag }}" + serverHost: {{ .Values.pmm.serverHost }} + replsets: + {{- range $k,$replset := .Values.replsets }} + {{- if $replset.name }} + - name: {{ $replset.name }} + {{- else }} + - name: {{ $k }} + {{- end }} + size: {{ $replset.size }} + {{- if $replset.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ $replset.terminationGracePeriodSeconds }} + {{- end }} + {{- if $replset.externalNodes }} + externalNodes: +{{ $replset.externalNodes | toYaml | indent 6 }} + {{- end }} + {{- if $replset.configuration }} + configuration: | +{{ $replset.configuration | indent 6 }} + {{- end }} + {{- if $replset.topologySpreadConstraints }} + topologySpreadConstraints: +{{ $replset.topologySpreadConstraints | toYaml | indent 6 }} + {{- end }} + {{- if $replset.serviceAccountName }} + serviceAccountName: {{ $replset.serviceAccountName }} + {{- end }} + {{- if $replset.affinity }} + affinity: +{{ $replset.affinity | toYaml | indent 6 }} + {{- end }} + {{- if $replset.priorityClass }} + priorityClassName: {{ $replset.priorityClass }} + {{- end }} + {{- if $replset.annotations }} + annotations: +{{ $replset.annotations | toYaml | indent 6 }} + {{- end }} + {{- if $replset.labels }} + labels: +{{ $replset.labels | toYaml | indent 6 }} + {{- end }} + {{- if $replset.nodeSelector }} + nodeSelector: +{{ $replset.nodeSelector | toYaml | indent 6 }} + {{- end }} + {{- if $replset.tolerations }} + tolerations: +{{ $replset.tolerations | toYaml | indent 6 }} + {{- end }} + {{- if $replset.livenessProbe }} + livenessProbe: +{{ $replset.livenessProbe | toYaml | indent 6 }} + {{- end }} + {{- if $replset.readinessProbe }} + readinessProbe: +{{ $replset.readinessProbe | toYaml | indent 6 }} + {{- end }} + {{- if $replset.storage }} + storage: +{{ $replset.storage | toYaml | indent 6 }} + {{- end }} + {{- if $replset.podSecurityContext }} + podSecurityContext: +{{ $replset.podSecurityContext | toYaml | indent 6 }} + {{- end }} + {{- if $replset.containerSecurityContext }} + containerSecurityContext: +{{ $replset.containerSecurityContext | toYaml | indent 6 }} + {{- end }} + {{- if $replset.runtimeClass }} + runtimeClassName: {{ $replset.runtimeClass }} + {{- end }} + {{- if $replset.sidecars }} + sidecars: +{{ $replset.sidecars | toYaml | indent 6 }} + {{- end }} + {{- if $replset.sidecarVolumes }} + sidecarVolumes: +{{ $replset.sidecarVolumes | toYaml | indent 6 }} + {{- end }} + {{- if $replset.sidecarPVCs }} + sidecarPVCs: +{{ $replset.sidecarPVCs | toYaml | indent 6 }} + {{- end }} + {{- if $replset.podDisruptionBudget }} + podDisruptionBudget: + {{- if $replset.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ $replset.podDisruptionBudget.maxUnavailable }} + {{- else }} + minAvailable: {{ $replset.podDisruptionBudget.minAvailable }} + {{- end }} + {{- end }} + {{- if $replset.splitHorizons }} + splitHorizons: +{{ $replset.splitHorizons | toYaml | indent 6 }} + {{- end }} + {{- if $replset.expose }} + expose: + enabled: {{ $replset.expose.enabled }} + exposeType: {{ $replset.expose.exposeType }} + {{- if $replset.expose.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ $replset.expose.loadBalancerSourceRanges | toYaml | indent 8 }} + {{- end }} + {{- if $replset.expose.serviceAnnotations }} + serviceAnnotations: +{{ $replset.expose.serviceAnnotations | toYaml | indent 8 }} + {{- end }} + {{- if $replset.expose.serviceLabels }} + serviceLabels: +{{ $replset.expose.serviceLabels | toYaml | indent 8 }} + {{- end }} + {{- end }} + {{- if $replset.schedulerName }} + schedulerName: {{ $replset.schedulerName }} + {{- end }} + resources: + {{- if $replset.resources }} +{{ $replset.resources | toYaml | indent 6 }} + {{- end }} + volumeSpec: + {{- if $replset.volumeSpec }} + {{- if $replset.volumeSpec.hostPath }} + hostPath: + path: {{ $replset.volumeSpec.hostPath.path }} + {{- if $replset.volumeSpec.hostPath.type }} + type: {{ $replset.volumeSpec.hostPath.type }} + {{- else }} + type: Directory + {{- end }} + {{- else if $replset.volumeSpec.pvc }} + persistentVolumeClaim: +{{ $replset.volumeSpec.pvc | toYaml | indent 8 }} + {{- else }} + emptyDir: {} + {{- end }} + {{- end }} + {{- if $replset.hostAliases }} + hostAliases: +{{ $replset.hostAliases | toYaml | indent 6 }} + {{- end }} + {{- if $replset.nonvoting }} + nonvoting: + enabled: {{ $replset.nonvoting.enabled }} + size: {{ $replset.nonvoting.size }} + {{- if $replset.nonvoting.configuration }} + configuration: | +{{ $replset.nonvoting.configuration | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.serviceAccountName }} + serviceAccountName: {{ $replset.nonvoting.serviceAccountName }} + {{- end }} + affinity: + {{- if $replset.nonvoting.affinity }} +{{ $replset.nonvoting.affinity | toYaml | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.priorityClass }} + priorityClassName: {{ $replset.nonvoting.priorityClass }} + {{- end }} + {{- if $replset.nonvoting.annotations }} + annotations: +{{ $replset.nonvoting.annotations | toYaml | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.labels }} + labels: +{{ $replset.nonvoting.labels | toYaml | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.podSecurityContext }} + podSecurityContext: +{{ $replset.nonvoting.podSecurityContext | toYaml | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.containerSecurityContext }} + containerSecurityContext: +{{ $replset.nonvoting.containerSecurityContext | toYaml | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.nodeSelector }} + nodeSelector: +{{ $replset.nonvoting.nodeSelector | toYaml | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.tolerations }} + tolerations: +{{ $replset.nonvoting.tolerations | toYaml | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.podDisruptionBudget }} + podDisruptionBudget: + {{- if $replset.nonvoting.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ $replset.nonvoting.podDisruptionBudget.maxUnavailable }} + {{- else }} + minAvailable: {{ $replset.nonvoting.podDisruptionBudget.minAvailable }} + {{- end }} + {{- end }} + {{- if $replset.nonvoting.resources }} + resources: +{{ $replset.nonvoting.resources | toYaml | indent 8 }} + {{- end }} + {{- if $replset.nonvoting.volumeSpec }} + volumeSpec: + {{- if $replset.nonvoting.volumeSpec.hostPath }} + hostPath: + path: {{ $replset.nonvoting.volumeSpec.hostPath.path }} + {{- if $replset.nonvoting.volumeSpec.hostPath.type }} + type: {{ $replset.nonvoting.volumeSpec.hostPath.type }} + {{- else }} + type: Directory + {{- end }} + {{- else if $replset.nonvoting.volumeSpec.pvc }} + persistentVolumeClaim: +{{ $replset.nonvoting.volumeSpec.pvc | toYaml | indent 10 }} + {{- else }} + emptyDir: {} + {{- end }} + {{- end }} + {{- end }} + {{- if $replset.arbiter }} + arbiter: + enabled: {{ $replset.arbiter.enabled }} + size: {{ $replset.arbiter.size }} + {{- if $replset.arbiter.serviceAccountName }} + serviceAccountName: {{ $replset.arbiter.serviceAccountName }} + {{- end }} + {{- if $replset.affinity }} + affinity: +{{ $replset.arbiter.affinity | toYaml | indent 8 }} + {{- end }} + {{- if $replset.arbiter.priorityClass }} + priorityClassName: {{ $replset.arbiter.priorityClass }} + {{- end }} + {{- if $replset.arbiter.annotations }} + annotations: +{{ $replset.arbiter.annotations | toYaml | indent 8 }} + {{- end }} + {{- if $replset.arbiter.labels }} + labels: +{{ $replset.arbiter.labels | toYaml | indent 8 }} + {{- end }} + {{- if $replset.arbiter.nodeSelector }} + nodeSelector: +{{ $replset.arbiter.nodeSelector | toYaml | indent 8 }} + {{- end }} + {{- if $replset.arbiter.tolerations }} + tolerations: +{{ $replset.arbiter.tolerations | toYaml | indent 8 }} + {{- end }} + {{- end }} + {{- end }} + + sharding: + enabled: {{ .Values.sharding.enabled }} + balancer: + enabled: {{ .Values.sharding.balancer.enabled }} + + configsvrReplSet: + size: {{ .Values.sharding.configrs.size }} + {{- if .Values.sharding.configrs.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.sharding.configrs.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.sharding.configrs.externalNodes }} + externalNodes: +{{ .Values.sharding.configrs.externalNodes | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.configuration }} + configuration: | +{{ .Values.sharding.configrs.configuration | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.topologySpreadConstraints }} + topologySpreadConstraints: +{{ .Values.sharding.configrs.topologySpreadConstraints | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.serviceAccountName }} + serviceAccountName: {{ .Values.sharding.configrs.serviceAccountName }} + {{- end }} + affinity: +{{ .Values.sharding.configrs.affinity | toYaml | indent 8 }} + {{- if .Values.sharding.configrs.priorityClass }} + priorityClassName: {{ .Values.sharding.configrs.priorityClass }} + {{- end }} + {{- if .Values.sharding.configrs.annotations }} + annotations: +{{ .Values.sharding.configrs.annotations | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.labels }} + labels: +{{ .Values.sharding.configrs.labels | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.nodeSelector }} + nodeSelector: +{{ .Values.sharding.configrs.nodeSelector | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.tolerations }} + tolerations: +{{ .Values.sharding.configrs.tolerations | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.livenessProbe }} + livenessProbe: +{{ .Values.sharding.configrs.livenessProbe | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.readinessProbe }} + readinessProbe: +{{ .Values.sharding.configrs.readinessProbe | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.storage }} + storage: +{{ .Values.sharding.configrs.storage | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.podSecurityContext }} + podSecurityContext: +{{ .Values.sharding.configrs.podSecurityContext | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.containerSecurityContext }} + containerSecurityContext: +{{ .Values.sharding.configrs.containerSecurityContext | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.runtimeClass }} + runtimeClassName: {{ .Values.sharding.configrs.runtimeClass }} + {{- end }} + {{- if .Values.sharding.configrs.sidecars }} + sidecars: +{{ .Values.sharding.configrs.sidecars | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.sidecarVolumes }} + sidecarVolumes: +{{ .Values.sharding.configrs.sidecarVolumes | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.sidecarPVCs }} + sidecarPVCs: +{{ .Values.sharding.configrs.sidecarPVCs | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.configrs.podDisruptionBudget }} + podDisruptionBudget: + {{- if .Values.sharding.configrs.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.sharding.configrs.podDisruptionBudget.maxUnavailable }} + {{- else }} + minAvailable: {{ .Values.sharding.configrs.podDisruptionBudget.minAvailable }} + {{- end }} + {{- end }} + {{- if .Values.sharding.configrs.expose }} + expose: + enabled: {{ .Values.sharding.configrs.expose.enabled }} + exposeType: {{ .Values.sharding.configrs.expose.exposeType }} + {{- if .Values.sharding.configrs.expose.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ .Values.sharding.configrs.expose.loadBalancerSourceRanges | toYaml | indent 10 }} + {{- end }} + {{- if .Values.sharding.configrs.expose.serviceAnnotations }} + serviceAnnotations: +{{ .Values.sharding.configrs.expose.serviceAnnotations | toYaml | indent 10 }} + {{- end }} + {{- if .Values.sharding.configrs.expose.serviceLabels }} + serviceLabels: +{{ .Values.sharding.configrs.expose.serviceLabels | toYaml | indent 10 }} + {{- end }} + {{- end }} + resources: + limits: + cpu: {{ .Values.sharding.configrs.resources.limits.cpu }} + memory: {{ .Values.sharding.configrs.resources.limits.memory }} + requests: + cpu: {{ .Values.sharding.configrs.resources.requests.cpu }} + memory: {{ .Values.sharding.configrs.resources.requests.memory }} + volumeSpec: + {{- if .Values.sharding.configrs.volumeSpec.hostPath }} + hostPath: + path: {{ .Values.sharding.configrs.volumeSpec.hostPath.path }} + {{- if .Values.sharding.configrs.volumeSpec.hostPath.type }} + type: {{ .Values.sharding.configrs.volumeSpec.hostPath.type }} + {{- else }} + type: Directory + {{- end }} + {{- else if .Values.sharding.configrs.volumeSpec.pvc }} + persistentVolumeClaim: +{{ .Values.sharding.configrs.volumeSpec.pvc | toYaml | indent 10 }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.sharding.configrs.hostAliases }} + hostAliases: +{{ .Values.sharding.configrs.hostAliases | toYaml | indent 8 }} + {{- end }} + + mongos: + size: {{ .Values.sharding.mongos.size }} + {{- if .Values.sharding.mongos.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.sharding.mongos.terminationGracePeriodSeconds }} + {{- end }} + {{- if .Values.sharding.mongos.configuration }} + configuration: | +{{ .Values.sharding.mongos.configuration | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.topologySpreadConstraints }} + topologySpreadConstraints: +{{ .Values.sharding.mongos.topologySpreadConstraints | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.serviceAccountName }} + serviceAccountName: {{ .Values.sharding.mongos.serviceAccountName }} + {{- end }} + affinity: +{{ .Values.sharding.mongos.affinity | toYaml | indent 8 }} + {{- if .Values.sharding.mongos.priorityClass }} + priorityClassName: {{ .Values.sharding.mongos.priorityClass }} + {{- end }} + {{- if .Values.sharding.mongos.annotations }} + annotations: +{{ .Values.sharding.mongos.annotations | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.labels }} + labels: +{{ .Values.sharding.mongos.labels | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.nodeSelector }} + nodeSelector: +{{ .Values.sharding.mongos.nodeSelector | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.tolerations }} + tolerations: +{{ .Values.sharding.mongos.tolerations | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.livenessProbe }} + livenessProbe: +{{ .Values.sharding.mongos.livenessProbe | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.readinessProbe }} + readinessProbe: +{{ .Values.sharding.mongos.readinessProbe | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.podSecurityContext }} + podSecurityContext: +{{ .Values.sharding.mongos.podSecurityContext | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.containerSecurityContext }} + containerSecurityContext: +{{ .Values.sharding.mongos.containerSecurityContext | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.runtimeClass }} + runtimeClassName: {{ .Values.sharding.mongos.runtimeClass }} + {{- end }} + {{- if .Values.sharding.mongos.sidecars }} + sidecars: +{{ .Values.sharding.mongos.sidecars | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.sidecarVolumes }} + sidecarVolumes: +{{ .Values.sharding.mongos.sidecarVolumes | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.sidecarPVCs }} + sidecarPVCs: +{{ .Values.sharding.mongos.sidecarPVCs | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.podDisruptionBudget }} + podDisruptionBudget: + {{- if .Values.sharding.mongos.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.sharding.mongos.podDisruptionBudget.maxUnavailable }} + {{- else }} + minAvailable: {{ .Values.sharding.mongos.podDisruptionBudget.minAvailable }} + {{- end }} + {{- end }} + resources: + limits: + cpu: {{ .Values.sharding.mongos.resources.limits.cpu }} + memory: {{ .Values.sharding.mongos.resources.limits.memory }} + requests: + cpu: {{ .Values.sharding.mongos.resources.requests.cpu }} + memory: {{ .Values.sharding.mongos.resources.requests.memory }} + expose: + exposeType: {{ .Values.sharding.mongos.expose.exposeType }} + {{- if .Values.sharding.mongos.expose.servicePerPod }} + servicePerPod: {{ .Values.sharding.mongos.expose.servicePerPod }} + {{- end }} + {{- if .Values.sharding.mongos.expose.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ .Values.sharding.mongos.expose.loadBalancerSourceRanges | toYaml | indent 10 }} + {{- end }} + {{- if .Values.sharding.mongos.expose.serviceAnnotations }} + serviceAnnotations: +{{ .Values.sharding.mongos.expose.serviceAnnotations | toYaml | indent 10 }} + {{- end }} + {{- if .Values.sharding.mongos.expose.serviceLabels }} + serviceLabels: +{{ .Values.sharding.mongos.expose.serviceLabels | toYaml | indent 10 }} + {{- end }} + {{- if .Values.sharding.mongos.expose.nodePort }} + nodePort: {{ .Values.sharding.mongos.expose.nodePort }} + {{- end }} + {{- if .Values.sharding.mongos.auditLog }} + auditLog: +{{ .Values.sharding.mongos.auditLog | toYaml | indent 8 }} + {{- end }} + {{- if .Values.sharding.mongos.hostAliases }} + hostAliases: +{{ .Values.sharding.mongos.hostAliases | toYaml | indent 8 }} + {{- end }} + + backup: + enabled: {{ .Values.backup.enabled }} + {{- if .Values.backup.annotations }} + annotations: +{{ .Values.backup.annotations | toYaml | indent 6 }} + {{- end }} + {{- if .Values.backup.podSecurityContext }} + podSecurityContext: +{{ .Values.backup.podSecurityContext | toYaml | indent 6 }} + {{- end }} + {{- if .Values.backup.containerSecurityContext }} + containerSecurityContext: +{{ .Values.backup.containerSecurityContext | toYaml | indent 6 }} + {{- end }} + image: "{{ .Values.backup.image.repository }}:{{ .Values.backup.image.tag }}" + {{- if .Values.backup.resources }} + resources: +{{ .Values.backup.resources | toYaml | indent 6 }} + {{- end }} + storages: +{{ .Values.backup.storages | toYaml | indent 6 }} + pitr: + {{- if and .Values.backup.enabled .Values.backup.pitr.enabled }} + enabled: true + {{- if .Values.backup.pitr.oplogOnly }} + oplogOnly: {{ .Values.backup.pitr.oplogOnly }} + {{- end }} + {{- if .Values.backup.pitr.oplogSpanMin }} + oplogSpanMin: {{ .Values.backup.pitr.oplogSpanMin }} + {{- end }} + {{- if .Values.backup.pitr.compressionType }} + compressionType: {{ .Values.backup.pitr.compressionType }} + {{- end }} + {{- if .Values.backup.pitr.compressionLevel }} + compressionLevel: {{ .Values.backup.pitr.compressionLevel }} + {{- end }} + {{- else }} + enabled: false + {{- end }} + {{- if .Values.backup.configuration }} + configuration: +{{ .Values.backup.configuration | toYaml | indent 6 }} + {{- end }} + tasks: +{{ .Values.backup.tasks | toYaml | indent 6 }} diff --git a/charts/percona/psmdb-db/1.16.3/values.yaml b/charts/percona/psmdb-db/1.16.3/values.yaml new file mode 100644 index 000000000..b06f67766 --- /dev/null +++ b/charts/percona/psmdb-db/1.16.3/values.yaml @@ -0,0 +1,593 @@ +# Default values for psmdb-cluster. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Platform type: kubernetes, openshift +# platform: kubernetes + +# Cluster DNS Suffix +# clusterServiceDNSSuffix: svc.cluster.local +# clusterServiceDNSMode: "Internal" + +finalizers: +## Set this if you want that operator deletes the primary pod last + - delete-psmdb-pods-in-order +## Set this if you want to delete database persistent volumes on cluster deletion +# - delete-psmdb-pvc + +nameOverride: "" +fullnameOverride: "" + +crVersion: 1.16.2 +pause: false +unmanaged: false +unsafeFlags: + tls: false + replsetSize: false + mongosSize: false + terminationGracePeriod: false + backupIfUnhealthy: false + +annotations: {} + +# ignoreAnnotations: +# - service.beta.kubernetes.io/aws-load-balancer-backend-protocol +# ignoreLabels: +# - rack +multiCluster: + enabled: false + # DNSSuffix: svc.clusterset.local +updateStrategy: SmartUpdate +upgradeOptions: + versionServiceEndpoint: https://check.percona.com + apply: disabled + schedule: "0 2 * * *" + setFCV: false + +image: + repository: percona/percona-server-mongodb + tag: 7.0.8-5 + +imagePullPolicy: Always +# imagePullSecrets: [] +# initImage: +# repository: percona/percona-server-mongodb-operator +# tag: 1.14.0 +# initContainerSecurityContext: {} +# tls: +# mode: preferTLS +# # 90 days in hours +# certValidityDuration: 2160h +# allowInvalidCertificates: true +# issuerConf: +# name: special-selfsigned-issuer +# kind: ClusterIssuer +# group: cert-manager.io +secrets: {} + # If you set users secret here the operator will use existing one or generate random values + # If not set the operator generates the default secret with name -secrets + # users: my-cluster-name-secrets + # encryptionKey: my-cluster-name-mongodb-encryption-key + # vault: my-cluster-name-vault + # ldapSecret: my-ldap-secret + # sse: my-cluster-name-sse + +pmm: + enabled: false + image: + repository: percona/pmm-client + tag: 2.41.2 + serverHost: monitoring-service + +replsets: + rs0: + name: rs0 + size: 3 + # terminationGracePeriodSeconds: 300 + # externalNodes: + # - host: 34.124.76.90 + # - host: 34.124.76.91 + # port: 27017 + # votes: 0 + # priority: 0 + # - host: 34.124.76.92 + # configuration: | + # operationProfiling: + # mode: slowOp + # systemLog: + # verbosity: 1 + # serviceAccountName: percona-server-mongodb-operator + # topologySpreadConstraints: + # - labelSelector: + # matchLabels: + # app.kubernetes.io/name: percona-server-mongodb + # maxSkew: 1 + # topologyKey: kubernetes.io/hostname + # whenUnsatisfiable: DoNotSchedule + affinity: + antiAffinityTopologyKey: "kubernetes.io/hostname" + # advanced: + # podAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # - labelSelector: + # matchExpressions: + # - key: security + # operator: In + # values: + # - S1 + # topologyKey: failure-domain.beta.kubernetes.io/zone + # tolerations: [] + # priorityClass: "" + # annotations: {} + # labels: {} + # podSecurityContext: {} + # containerSecurityContext: {} + # nodeSelector: {} + # livenessProbe: + # failureThreshold: 4 + # initialDelaySeconds: 60 + # periodSeconds: 30 + # timeoutSeconds: 10 + # startupDelaySeconds: 7200 + # readinessProbe: + # failureThreshold: 8 + # initialDelaySeconds: 10 + # periodSeconds: 3 + # successThreshold: 1 + # timeoutSeconds: 2 + # runtimeClassName: image-rc + # storage: + # engine: wiredTiger + # wiredTiger: + # engineConfig: + # cacheSizeRatio: 0.5 + # directoryForIndexes: false + # journalCompressor: snappy + # collectionConfig: + # blockCompressor: snappy + # indexConfig: + # prefixCompression: true + # inMemory: + # engineConfig: + # inMemorySizeRatio: 0.5 + # sidecars: + # - image: busybox + # command: ["/bin/sh"] + # args: ["-c", "while true; do echo echo $(date -u) 'test' >> /dev/null; sleep 5;done"] + # name: rs-sidecar-1 + # volumeMounts: + # - mountPath: /volume1 + # name: sidecar-volume-claim + # - mountPath: /secret + # name: sidecar-secret + # - mountPath: /configmap + # name: sidecar-config + # sidecarVolumes: + # - name: sidecar-secret + # secret: + # secretName: mysecret + # - name: sidecar-config + # configMap: + # name: myconfigmap + # sidecarPVCs: + # - apiVersion: v1 + # kind: PersistentVolumeClaim + # metadata: + # name: sidecar-volume-claim + # spec: + # resources: + # requests: + # storage: 1Gi + # volumeMode: Filesystem + # accessModes: + # - ReadWriteOnce + podDisruptionBudget: + maxUnavailable: 1 + # splitHorizons: + # my-cluster-name-rs0-0: + # external: rs0-0.mycluster.xyz + # external-2: rs0-0.mycluster2.xyz + # my-cluster-name-rs0-1: + # external: rs0-1.mycluster.xyz + # external-2: rs0-1.mycluster2.xyz + # my-cluster-name-rs0-2: + # external: rs0-2.mycluster.xyz + # external-2: rs0-2.mycluster2.xyz + expose: + enabled: false + exposeType: ClusterIP + # loadBalancerSourceRanges: + # - 10.0.0.0/8 + # serviceAnnotations: + # service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http + # serviceLabels: + # some-label: some-key + # schedulerName: "" + resources: + limits: + cpu: "300m" + memory: "0.5G" + requests: + cpu: "300m" + memory: "0.5G" + volumeSpec: + # emptyDir: {} + # hostPath: + # path: /data + # type: Directory + pvc: + # annotations: + # volume.beta.kubernetes.io/storage-class: example-hostpath + # labels: + # rack: rack-22 + # storageClassName: standard + # accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 3Gi + # hostAliases: + # - ip: "10.10.0.2" + # hostnames: + # - "host1" + # - "host2" + nonvoting: + enabled: false + # podSecurityContext: {} + # containerSecurityContext: {} + size: 3 + # configuration: | + # operationProfiling: + # mode: slowOp + # systemLog: + # verbosity: 1 + # serviceAccountName: percona-server-mongodb-operator + affinity: + antiAffinityTopologyKey: "kubernetes.io/hostname" + # advanced: + # podAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # - labelSelector: + # matchExpressions: + # - key: security + # operator: In + # values: + # - S1 + # topologyKey: failure-domain.beta.kubernetes.io/zone + # tolerations: [] + # priorityClass: "" + # annotations: {} + # labels: {} + # nodeSelector: {} + podDisruptionBudget: + maxUnavailable: 1 + resources: + limits: + cpu: "300m" + memory: "0.5G" + requests: + cpu: "300m" + memory: "0.5G" + volumeSpec: + # emptyDir: {} + # hostPath: + # path: /data + # type: Directory + pvc: + # annotations: + # volume.beta.kubernetes.io/storage-class: example-hostpath + # labels: + # rack: rack-22 + # storageClassName: standard + # accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 3Gi + arbiter: + enabled: false + size: 1 + # serviceAccountName: percona-server-mongodb-operator + affinity: + antiAffinityTopologyKey: "kubernetes.io/hostname" + # advanced: + # podAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # - labelSelector: + # matchExpressions: + # - key: security + # operator: In + # values: + # - S1 + # topologyKey: failure-domain.beta.kubernetes.io/zone + # tolerations: [] + # priorityClass: "" + # annotations: {} + # labels: {} + # nodeSelector: {} + +sharding: + enabled: true + balancer: + enabled: true + + configrs: + size: 3 + # terminationGracePeriodSeconds: 300 + # externalNodes: + # - host: 34.124.76.90 + # - host: 34.124.76.91 + # port: 27017 + # votes: 0 + # priority: 0 + # - host: 34.124.76.92 + # configuration: | + # operationProfiling: + # mode: slowOp + # systemLog: + # verbosity: 1 + # serviceAccountName: percona-server-mongodb-operator + # topologySpreadConstraints: + # - labelSelector: + # matchLabels: + # app.kubernetes.io/name: percona-server-mongodb + # maxSkew: 1 + # topologyKey: kubernetes.io/hostname + # whenUnsatisfiable: DoNotSchedule + affinity: + antiAffinityTopologyKey: "kubernetes.io/hostname" + # advanced: + # podAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # - labelSelector: + # matchExpressions: + # - key: security + # operator: In + # values: + # - S1 + # topologyKey: failure-domain.beta.kubernetes.io/zone + # tolerations: [] + # priorityClass: "" + # annotations: {} + # labels: {} + # podSecurityContext: {} + # containerSecurityContext: {} + # nodeSelector: {} + # livenessProbe: {} + # readinessProbe: {} + # runtimeClassName: image-rc + # sidecars: + # - image: busybox + # command: ["/bin/sh"] + # args: ["-c", "while true; do echo echo $(date -u) 'test' >> /dev/null; sleep 5;done"] + # name: rs-sidecar-1 + # volumeMounts: + # - mountPath: /volume1 + # name: sidecar-volume-claim + # sidecarPVCs: [] + # sidecarVolumes: [] + podDisruptionBudget: + maxUnavailable: 1 + expose: + enabled: false + exposeType: ClusterIP + # loadBalancerSourceRanges: + # - 10.0.0.0/8 + # serviceAnnotations: + # service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http + # serviceLabels: + # some-label: some-key + resources: + limits: + cpu: "300m" + memory: "0.5G" + requests: + cpu: "300m" + memory: "0.5G" + volumeSpec: + # emptyDir: {} + # hostPath: + # path: /data + # type: Directory + pvc: + # annotations: + # volume.beta.kubernetes.io/storage-class: example-hostpath + # labels: + # rack: rack-22 + # storageClassName: standard + # accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: 3Gi + # hostAliases: + # - ip: "10.10.0.2" + # hostnames: + # - "host1" + # - "host2" + + mongos: + size: 2 + # terminationGracePeriodSeconds: 300 + # configuration: | + # systemLog: + # verbosity: 1 + # serviceAccountName: percona-server-mongodb-operator + # topologySpreadConstraints: + # - labelSelector: + # matchLabels: + # app.kubernetes.io/name: percona-server-mongodb + # maxSkew: 1 + # topologyKey: kubernetes.io/hostname + # whenUnsatisfiable: DoNotSchedule + affinity: + antiAffinityTopologyKey: "kubernetes.io/hostname" + # advanced: + # podAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # - labelSelector: + # matchExpressions: + # - key: security + # operator: In + # values: + # - S1 + # topologyKey: failure-domain.beta.kubernetes.io/zone + # tolerations: [] + # priorityClass: "" + # annotations: {} + # labels: {} + # podSecurityContext: {} + # containerSecurityContext: {} + # nodeSelector: {} + # livenessProbe: {} + # readinessProbe: {} + # runtimeClassName: image-rc + # sidecars: + # - image: busybox + # command: ["/bin/sh"] + # args: ["-c", "while true; do echo echo $(date -u) 'test' >> /dev/null; sleep 5;done"] + # name: rs-sidecar-1 + # volumeMounts: + # - mountPath: /volume1 + # name: sidecar-volume-claim + # sidecarPVCs: [] + # sidecarVolumes: [] + podDisruptionBudget: + maxUnavailable: 1 + resources: + limits: + cpu: "300m" + memory: "0.5G" + requests: + cpu: "300m" + memory: "0.5G" + expose: + exposeType: ClusterIP + # servicePerPod: true + # loadBalancerSourceRanges: + # - 10.0.0.0/8 + # serviceAnnotations: + # service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http + # serviceLabels: + # some-label: some-key + # nodePort: 32017 + # auditLog: + # destination: file + # format: BSON + # filter: '{}' + # hostAliases: + # - ip: "10.10.0.2" + # hostnames: + # - "host1" + # - "host2" + +backup: + enabled: true + image: + repository: percona/percona-backup-mongodb + tag: 2.4.1 + # annotations: + # iam.amazonaws.com/role: role-arn + # podSecurityContext: {} + # containerSecurityContext: {} + # resources: + # limits: + # cpu: "300m" + # memory: "0.5G" + # requests: + # cpu: "300m" + # memory: "0.5G" + storages: + # s3-us-west: + # type: s3 + # s3: + # bucket: S3-BACKUP-BUCKET-NAME-HERE + # credentialsSecret: my-cluster-name-backup-s3 + # serverSideEncryption: + # kmsKeyID: 1234abcd-12ab-34cd-56ef-1234567890ab + # sseAlgorithm: aws:kms + # sseCustomerAlgorithm: AES256 + # sseCustomerKey: Y3VzdG9tZXIta2V5 + # retryer: + # numMaxRetries: 3 + # minRetryDelay: 30ms + # maxRetryDelay: 5m + # region: us-west-2 + # prefix: "" + # uploadPartSize: 10485760 + # maxUploadParts: 10000 + # storageClass: STANDARD + # insecureSkipTLSVerify: false + # minio: + # type: s3 + # s3: + # bucket: MINIO-BACKUP-BUCKET-NAME-HERE + # region: us-east-1 + # credentialsSecret: my-cluster-name-backup-minio + # endpointUrl: http://minio.psmdb.svc.cluster.local:9000/minio/ + # prefix: "" + # azure-blob: + # type: azure + # azure: + # container: CONTAINER-NAME + # prefix: PREFIX-NAME + # endpointUrl: https://accountName.blob.core.windows.net + # credentialsSecret: SECRET-NAME + pitr: + enabled: false + oplogOnly: false + # oplogSpanMin: 10 + # compressionType: gzip + # compressionLevel: 6 + # configuration: + # backupOptions: + # priority: + # "localhost:28019": 2.5 + # "localhost:27018": 2.5 + # timeouts: + # startingStatus: 33 + # oplogSpanMin: 10 + # restoreOptions: + # batchSize: 500 + # numInsertionWorkers: 10 + # numDownloadWorkers: 4 + # maxDownloadBufferMb: 0 + # downloadChunkMb: 32 + # mongodLocation: /usr/bin/mongo + # mongodLocationMap: + # "node01:2017": /usr/bin/mongo + # "node03:27017": /usr/bin/mongo + tasks: + # - name: daily-s3-us-west + # enabled: true + # schedule: "0 0 * * *" + # keep: 3 + # storageName: s3-us-west + # compressionType: gzip + # - name: weekly-s3-us-west + # enabled: false + # schedule: "0 0 * * 0" + # keep: 5 + # storageName: s3-us-west + # compressionType: gzip + # - name: weekly-s3-us-west-physical + # enabled: false + # schedule: "0 5 * * 0" + # keep: 5 + # type: physical + # storageName: s3-us-west + # compressionType: gzip + # compressionLevel: 6 + +# If you set users here the secret will be constructed by helm with these values +# users: +# MONGODB_BACKUP_USER: backup +# MONGODB_BACKUP_PASSWORD: backup123456 +# MONGODB_DATABASE_ADMIN_USER: databaseAdmin +# MONGODB_DATABASE_ADMIN_PASSWORD: databaseAdmin123456 +# MONGODB_CLUSTER_ADMIN_USER: clusterAdmin +# MONGODB_CLUSTER_ADMIN_PASSWORD: clusterAdmin123456 +# MONGODB_CLUSTER_MONITOR_USER: clusterMonitor +# MONGODB_CLUSTER_MONITOR_PASSWORD: clusterMonitor123456 +# MONGODB_USER_ADMIN_USER: userAdmin +# MONGODB_USER_ADMIN_PASSWORD: userAdmin123456 +# PMM_SERVER_API_KEY: apikey +# # PMM_SERVER_USER: admin +# # PMM_SERVER_PASSWORD: admin diff --git a/charts/percona/psmdb-operator/1.16.3/.helmignore b/charts/percona/psmdb-operator/1.16.3/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/percona/psmdb-operator/1.16.3/Chart.yaml b/charts/percona/psmdb-operator/1.16.3/Chart.yaml new file mode 100644 index 000000000..dc3ea8a0c --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/Chart.yaml @@ -0,0 +1,20 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Percona Operator for MongoDB + catalog.cattle.io/kube-version: '>=1.21-0' + catalog.cattle.io/release-name: psmdb-operator +apiVersion: v2 +appVersion: 1.16.2 +description: A Helm chart for deploying the Percona Operator for MongoDB +home: https://docs.percona.com/percona-operator-for-mongodb/ +icon: file://assets/icons/psmdb-operator.png +kubeVersion: '>=1.21-0' +maintainers: +- email: tomislav.plavcic@percona.com + name: tplavcic +- email: natalia.marukovich@percona.com + name: nmarukovich +- email: sergey.pronin@percona.com + name: spron-in +name: psmdb-operator +version: 1.16.3 diff --git a/charts/percona/psmdb-operator/1.16.3/LICENSE.txt b/charts/percona/psmdb-operator/1.16.3/LICENSE.txt new file mode 100644 index 000000000..6a31453af --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/LICENSE.txt @@ -0,0 +1,13 @@ +Copyright 2019 Paul Czarkowski + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/charts/percona/psmdb-operator/1.16.3/README.md b/charts/percona/psmdb-operator/1.16.3/README.md new file mode 100644 index 000000000..e6341798a --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/README.md @@ -0,0 +1,69 @@ +# Percona Operator for MongoDB + +Percona Operator for MongoDB allows users to deploy and manage Percona Server for MongoDB Clusters on Kubernetes. +Useful links: +- [Operator Github repository](https://github.com/percona/percona-server-mongodb-operator) +- [Operator Documentation](https://www.percona.com/doc/kubernetes-operator-for-psmongodb/index.html) + +## Pre-requisites +* Kubernetes 1.26+ +* Helm v3 + +# Installation + +This chart will deploy the Operator Pod for the further Percona Server for MongoDB creation in Kubernetes. + +## Installing the chart + +To install the chart with the `psmdb` release name using a dedicated namespace (recommended): + +```sh +helm repo add percona https://percona.github.io/percona-helm-charts/ +helm install my-operator percona/psmdb-operator --version 1.16.2 --namespace my-namespace +``` + +The chart can be customized using the following configurable parameters: + +| Parameter | Description | Default | +| ------------------------------- | ------------------------------------------------------------------------------| ------------------------------------------| +| `image.repository` | PSMDB Operator Container image name | `percona/percona-server-mongodb-operator` | +| `image.tag` | PSMDB Operator Container image tag | `1.16.2` | +| `image.pullPolicy` | PSMDB Operator Container pull policy | `Always` | +| `image.pullSecrets` | PSMDB Operator Pod pull secret | `[]` | +| `replicaCount` | PSMDB Operator Pod quantity | `1` | +| `tolerations` | List of node taints to tolerate | `[]` | +| `annotations` | PSMDB Operator Deployment annotations | `{}` | +| `podAnnotations` | PSMDB Operator Pod annotations | `{}` | +| `labels` | PSMDB Operator Deployment labels | `{}` | +| `podLabels` | PSMDB Operator Pod labels | `{}` | +| `resources` | Resource requests and limits | `{}` | +| `nodeSelector` | Labels for Pod assignment | `{}` | +| `podAnnotations` | Annotations for pod | `{}` | +| `podSecurityContext` | Pod Security Context | `{}` | +| `watchNamespace` | Set when a different from default namespace is needed to watch (comma separated if multiple needed) | `""` | +| `createNamespace` | Set if you want to create watched namespaces with helm | `false` | +| `rbac.create` | If false RBAC will not be created. RBAC resources will need to be created manually | `true` | +| `securityContext` | Container Security Context | `{}` | +| `serviceAccount.create` | If false the ServiceAccounts will not be created. The ServiceAccounts must be created manually | `true` | +| `serviceAccount.annotations` | PSMDB Operator ServiceAccount annotations | `{}` | +| `logStructured` | Force PSMDB operator to print JSON-wrapped log messages | `false` | +| `logLevel` | PSMDB Operator logging level | `INFO` | +| `disableTelemetry` | Disable sending PSMDB Operator telemetry data to Percona | `false` | + +Specify parameters using `--set key=value[,key=value]` argument to `helm install` + +Alternatively a YAML file that specifies the values for the parameters can be provided like this: + +```sh +helm install psmdb-operator -f values.yaml percona/psmdb-operator +``` + +## Deploy the database + +To deploy Percona Server for MongoDB run the following command: + +```sh +helm install my-db percona/psmdb-db +``` + +See more about Percona Server for MongoDB deployment in its chart [here](https://github.com/percona/percona-helm-charts/tree/main/charts/psmdb-db) or in the [Helm chart installation guide](https://www.percona.com/doc/kubernetes-operator-for-psmongodb/helm.html). diff --git a/charts/percona/psmdb-operator/1.16.3/crds/crd.yaml b/charts/percona/psmdb-operator/1.16.3/crds/crd.yaml new file mode 100644 index 000000000..dcda377e5 --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/crds/crd.yaml @@ -0,0 +1,18967 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: perconaservermongodbbackups.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDBBackup + listKind: PerconaServerMongoDBBackupList + plural: perconaservermongodbbackups + shortNames: + - psmdb-backup + singular: perconaservermongodbbackup + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Cluster name + jsonPath: .spec.clusterName + name: Cluster + type: string + - description: Storage name + jsonPath: .spec.storageName + name: Storage + type: string + - description: Backup destination + jsonPath: .status.destination + name: Destination + type: string + - description: Backup type + jsonPath: .status.type + name: Type + type: string + - description: Job status + jsonPath: .status.state + name: Status + type: string + - description: Completed time + jsonPath: .status.completed + name: Completed + type: date + - description: Created time + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + clusterName: + type: string + compressionLevel: + type: integer + compressionType: + type: string + psmdbCluster: + type: string + storageName: + type: string + type: + enum: + - logical + - physical + type: string + type: object + status: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + completed: + format: date-time + type: string + destination: + type: string + error: + type: string + lastTransition: + format: date-time + type: string + latestRestorableTime: + format: date-time + type: string + pbmName: + type: string + pbmPod: + type: string + pbmPods: + additionalProperties: + type: string + type: object + replsetNames: + items: + type: string + type: array + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + start: + format: date-time + type: string + state: + type: string + storageName: + type: string + type: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: perconaservermongodbrestores.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDBRestore + listKind: PerconaServerMongoDBRestoreList + plural: perconaservermongodbrestores + shortNames: + - psmdb-restore + singular: perconaservermongodbrestore + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Cluster name + jsonPath: .spec.clusterName + name: Cluster + type: string + - description: Job status + jsonPath: .status.state + name: Status + type: string + - description: Created time + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + backupName: + type: string + backupSource: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + completed: + format: date-time + type: string + destination: + type: string + error: + type: string + lastTransition: + format: date-time + type: string + latestRestorableTime: + format: date-time + type: string + pbmName: + type: string + pbmPod: + type: string + pbmPods: + additionalProperties: + type: string + type: object + replsetNames: + items: + type: string + type: array + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + start: + format: date-time + type: string + state: + type: string + storageName: + type: string + type: + type: string + type: object + clusterName: + type: string + pitr: + properties: + date: + type: string + type: + type: string + type: object + replset: + type: string + storageName: + type: string + type: object + status: + properties: + completed: + format: date-time + type: string + error: + type: string + lastTransition: + format: date-time + type: string + pbmName: + type: string + pitrTarget: + type: string + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: perconaservermongodbs.psmdb.percona.com +spec: + group: psmdb.percona.com + names: + kind: PerconaServerMongoDB + listKind: PerconaServerMongoDBList + plural: perconaservermongodbs + shortNames: + - psmdb + singular: perconaservermongodb + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-2-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-2-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-3-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-3-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-4-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-4-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-5-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-5-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-6-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-6-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-7-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-7-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-8-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-8-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-9-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-9-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: false + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-10-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-10-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-11-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-11-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: psmdb.percona.com/v1-12-0 PerconaServerMongoDB is deprecated + and will be removed in v1.17.0; see v1.13.0 release notes for instructions to + migrate to psmdb.percona.com/v1 + name: v1-12-0 + schema: + openAPIV3Schema: + properties: + spec: + type: object + x-kubernetes-preserve-unknown-fields: true + status: + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .status.host + name: ENDPOINT + type: string + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + allowUnsafeConfigurations: + type: boolean + backup: + properties: + annotations: + additionalProperties: + type: string + type: object + configuration: + properties: + backupOptions: + properties: + oplogSpanMin: + type: number + priority: + additionalProperties: + type: number + type: object + timeouts: + properties: + startingStatus: + format: int32 + type: integer + type: object + required: + - oplogSpanMin + type: object + restoreOptions: + properties: + batchSize: + type: integer + downloadChunkMb: + type: integer + maxDownloadBufferMb: + type: integer + mongodLocation: + type: string + mongodLocationMap: + additionalProperties: + type: string + type: object + numDownloadWorkers: + type: integer + numInsertionWorkers: + type: integer + type: object + type: object + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + image: + type: string + labels: + additionalProperties: + type: string + type: object + pitr: + properties: + compressionLevel: + type: integer + compressionType: + type: string + enabled: + type: boolean + oplogOnly: + type: boolean + oplogSpanMin: + type: number + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + storages: + additionalProperties: + properties: + azure: + properties: + container: + type: string + credentialsSecret: + type: string + endpointUrl: + type: string + prefix: + type: string + required: + - credentialsSecret + type: object + s3: + properties: + bucket: + type: string + credentialsSecret: + type: string + debugLogLevels: + type: string + endpointUrl: + type: string + forcePathStyle: + type: boolean + insecureSkipTLSVerify: + type: boolean + maxUploadParts: + type: integer + prefix: + type: string + region: + type: string + retryer: + properties: + maxRetryDelay: + type: string + minRetryDelay: + type: string + numMaxRetries: + type: integer + type: object + serverSideEncryption: + properties: + kmsKeyID: + type: string + sseAlgorithm: + type: string + sseCustomerAlgorithm: + type: string + sseCustomerKey: + type: string + type: object + storageClass: + type: string + uploadPartSize: + type: integer + required: + - bucket + type: object + type: + type: string + required: + - type + type: object + type: object + tasks: + items: + properties: + compressionLevel: + type: integer + compressionType: + type: string + enabled: + type: boolean + keep: + type: integer + name: + type: string + schedule: + type: string + storageName: + type: string + type: + enum: + - logical + - physical + type: string + required: + - enabled + - name + type: object + type: array + required: + - enabled + - image + type: object + clusterServiceDNSMode: + type: string + clusterServiceDNSSuffix: + type: string + crVersion: + type: string + ignoreAnnotations: + items: + type: string + type: array + ignoreLabels: + items: + type: string + type: array + image: + type: string + imagePullPolicy: + type: string + imagePullSecrets: + items: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + initImage: + type: string + multiCluster: + properties: + DNSSuffix: + type: string + enabled: + type: boolean + required: + - enabled + type: object + pause: + type: boolean + platform: + type: string + pmm: + properties: + enabled: + type: boolean + image: + type: string + mongodParams: + type: string + mongosParams: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + serverHost: + type: string + required: + - image + type: object + replsets: + items: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + arbiter: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + priorityClassName: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + required: + - enabled + - size + type: object + clusterRole: + type: string + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + enabled: + type: boolean + exposeType: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + nodePort: + format: int32 + type: integer + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + required: + - enabled + type: object + externalNodes: + items: + properties: + host: + type: string + port: + type: integer + priority: + type: integer + votes: + type: integer + required: + - host + - priority + - votes + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + type: object + type: array + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + nonvoting: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + splitHorizons: + additionalProperties: + additionalProperties: + type: string + type: object + type: object + storage: + properties: + directoryPerDB: + type: boolean + engine: + type: string + inMemory: + properties: + engineConfig: + properties: + inMemorySizeRatio: + type: number + type: object + type: object + mmapv1: + properties: + nsSize: + type: integer + smallfiles: + type: boolean + type: object + syncPeriodSecs: + type: integer + wiredTiger: + properties: + collectionConfig: + properties: + blockCompressor: + type: string + type: object + engineConfig: + properties: + cacheSizeRatio: + type: number + directoryForIndexes: + type: boolean + journalCompressor: + type: string + type: object + indexConfig: + properties: + prefixCompression: + type: boolean + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - size + type: object + type: array + schedulerName: + type: string + secrets: + properties: + encryptionKey: + type: string + ldapSecret: + type: string + sse: + type: string + ssl: + type: string + sslInternal: + type: string + users: + type: string + vault: + type: string + type: object + sharding: + properties: + balancer: + properties: + enabled: + type: boolean + type: object + configsvrReplSet: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + arbiter: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + priorityClassName: + type: string + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + required: + - enabled + - size + type: object + clusterRole: + type: string + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + enabled: + type: boolean + exposeType: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + nodePort: + format: int32 + type: integer + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + required: + - enabled + type: object + externalNodes: + items: + properties: + host: + type: string + port: + type: integer + priority: + type: integer + votes: + type: integer + required: + - host + - priority + - votes + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + type: object + type: array + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + nonvoting: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + enabled: + type: boolean + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - enabled + - size + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + splitHorizons: + additionalProperties: + additionalProperties: + type: string + type: object + type: object + storage: + properties: + directoryPerDB: + type: boolean + engine: + type: string + inMemory: + properties: + engineConfig: + properties: + inMemorySizeRatio: + type: number + type: object + type: object + mmapv1: + properties: + nsSize: + type: integer + smallfiles: + type: boolean + type: object + syncPeriodSecs: + type: integer + wiredTiger: + properties: + collectionConfig: + properties: + blockCompressor: + type: string + type: object + engineConfig: + properties: + cacheSizeRatio: + type: number + directoryForIndexes: + type: boolean + journalCompressor: + type: string + type: object + indexConfig: + properties: + prefixCompression: + type: boolean + type: object + type: object + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + volumeSpec: + properties: + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + persistentVolumeClaim: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + annotations: + additionalProperties: + type: string + type: object + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + labels: + additionalProperties: + type: string + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + type: object + required: + - size + type: object + enabled: + type: boolean + mongos: + properties: + affinity: + properties: + advanced: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + podAntiAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + items: + type: string + type: array + x-kubernetes-list-type: atomic + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + x-kubernetes-list-type: atomic + type: object + type: object + antiAffinityTopologyKey: + type: string + type: object + annotations: + additionalProperties: + type: string + type: object + configuration: + type: string + containerSecurityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + expose: + properties: + exposeType: + type: string + loadBalancerSourceRanges: + items: + type: string + type: array + nodePort: + format: int32 + type: integer + serviceAnnotations: + additionalProperties: + type: string + type: object + serviceLabels: + additionalProperties: + type: string + type: object + servicePerPod: + type: boolean + type: object + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + x-kubernetes-list-type: atomic + ip: + type: string + type: object + type: array + hostPort: + format: int32 + type: integer + labels: + additionalProperties: + type: string + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + startupDelaySeconds: + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + nodeSelector: + additionalProperties: + type: string + type: object + podDisruptionBudget: + properties: + maxUnavailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + minAvailable: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + type: object + podSecurityContext: + properties: + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + x-kubernetes-list-type: atomic + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + port: + format: int32 + type: integer + priorityClassName: + type: string + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + runtimeClassName: + type: string + serviceAccountName: + type: string + setParameter: + properties: + cursorTimeoutMillis: + type: integer + type: object + sidecarPVCs: + items: + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + status: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + allocatedResourceStatuses: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + conditions: + items: + properties: + lastProbeTime: + format: date-time + type: string + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentVolumeAttributesClassName: + type: string + modifyVolumeStatus: + properties: + status: + type: string + targetVolumeAttributesClassName: + type: string + required: + - status + type: object + phase: + type: string + type: object + type: object + type: array + sidecarVolumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + x-kubernetes-list-type: atomic + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + namespace: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + type: string + volumeAttributesClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + x-kubernetes-list-type: atomic + wwids: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + x-kubernetes-list-type: atomic + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + clusterTrustBundle: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + name: + type: string + optional: + type: boolean + path: + type: string + signerName: + type: string + required: + - path + type: object + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + x-kubernetes-list-type: atomic + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + x-kubernetes-list-type: atomic + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + x-kubernetes-list-type: atomic + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + x-kubernetes-list-type: atomic + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + sidecars: + items: + properties: + args: + items: + type: string + type: array + x-kubernetes-list-type: atomic + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + x-kubernetes-list-type: atomic + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + sleep: + properties: + seconds: + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resizePolicy: + items: + properties: + resourceName: + type: string + restartPolicy: + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + properties: + claims: + items: + properties: + name: + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + restartPolicy: + type: string + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + appArmorProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + capabilities: + properties: + add: + items: + type: string + type: array + x-kubernetes-list-type: atomic + drop: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + x-kubernetes-list-type: atomic + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + x-kubernetes-list-type: atomic + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - devicePath + x-kubernetes-list-type: map + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + x-kubernetes-list-map-keys: + - mountPath + x-kubernetes-list-type: map + workingDir: + type: string + required: + - name + type: object + type: array + size: + format: int32 + type: integer + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchLabels: + additionalProperties: + type: string + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + format: int32 + type: integer + minDomains: + format: int32 + type: integer + nodeAffinityPolicy: + type: string + nodeTaintsPolicy: + type: string + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + type: object + required: + - enabled + type: object + tls: + properties: + allowInvalidCertificates: + type: boolean + certValidityDuration: + type: string + issuerConf: + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - name + type: object + mode: + type: string + type: object + unmanaged: + type: boolean + unsafeFlags: + properties: + backupIfUnhealthy: + type: boolean + mongosSize: + type: boolean + replsetSize: + type: boolean + terminationGracePeriod: + type: boolean + tls: + type: boolean + type: object + updateStrategy: + type: string + upgradeOptions: + properties: + apply: + type: string + schedule: + type: string + setFCV: + type: boolean + versionServiceEndpoint: + type: string + type: object + required: + - image + type: object + status: + properties: + backup: + type: string + backupVersion: + type: string + conditions: + items: + properties: + lastTransitionTime: + format: date-time + type: string + message: + type: string + reason: + type: string + status: + type: string + type: + type: string + required: + - status + - type + type: object + type: array + host: + type: string + message: + type: string + mongoImage: + type: string + mongoVersion: + type: string + mongos: + properties: + message: + type: string + ready: + type: integer + size: + type: integer + status: + type: string + required: + - ready + - size + type: object + observedGeneration: + format: int64 + type: integer + pmmStatus: + type: string + pmmVersion: + type: string + ready: + format: int32 + type: integer + replsets: + additionalProperties: + properties: + added_as_shard: + type: boolean + clusterRole: + type: string + initialized: + type: boolean + members: + items: + properties: + name: + type: string + version: + type: string + type: object + type: array + message: + type: string + ready: + format: int32 + type: integer + size: + format: int32 + type: integer + status: + type: string + required: + - ready + - size + type: object + type: object + size: + format: int32 + type: integer + state: + type: string + required: + - ready + - size + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/percona/psmdb-operator/1.16.3/templates/NOTES.txt b/charts/percona/psmdb-operator/1.16.3/templates/NOTES.txt new file mode 100644 index 000000000..f72a33c0d --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/templates/NOTES.txt @@ -0,0 +1,15 @@ +1. Percona Operator for MongoDB is deployed. + See if the operator Pod is running: + + kubectl get pods -l app.kubernetes.io/name=psmdb-operator --namespace {{ .Release.Namespace }} + + Check the operator logs if the Pod is not starting: + + export POD=$(kubectl get pods -l app.kubernetes.io/name=psmdb-operator --namespace {{ .Release.Namespace }} --output name) + kubectl logs $POD --namespace={{ .Release.Namespace }} + +2. Deploy the database cluster from psmdb-db chart: + + helm install my-db percona/psmdb-db --namespace={{ .Release.Namespace }} + +Read more in our documentation: https://docs.percona.com/percona-operator-for-mongodb/ diff --git a/charts/percona/psmdb-operator/1.16.3/templates/_helpers.tpl b/charts/percona/psmdb-operator/1.16.3/templates/_helpers.tpl new file mode 100644 index 000000000..1bf81ed17 --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/templates/_helpers.tpl @@ -0,0 +1,45 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "psmdb-operator.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 "psmdb-operator.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 "psmdb-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "psmdb-operator.labels" -}} +app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} +helm.sh/chart: {{ include "psmdb-operator.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} diff --git a/charts/percona/psmdb-operator/1.16.3/templates/deployment.yaml b/charts/percona/psmdb-operator/1.16.3/templates/deployment.yaml new file mode 100644 index 000000000..c70f73205 --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/templates/deployment.yaml @@ -0,0 +1,98 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "psmdb-operator.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "psmdb-operator.labels" . | nindent 4 }} + {{- with .Values.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + app.kubernetes.io/name: {{ include "psmdb-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "psmdb-operator.fullname" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - containerPort: 8080 + protocol: TCP + name: metrics + - containerPort: 8081 + protocol: TCP + name: health + command: + - percona-server-mongodb-operator + env: + - name: LOG_STRUCTURED + value: "{{ .Values.logStructured }}" + - name: LOG_LEVEL + value: "{{ .Values.logLevel }}" + - name: WATCH_NAMESPACE + {{- if .Values.watchAllNamespaces }} + value: "" + {{- else }} + value: "{{ default .Release.Namespace .Values.watchNamespace }}" + {{- end }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: OPERATOR_NAME + value: {{ default "percona-server-mongodb-operator" .Values.operatorName }} + - name: RESYNC_PERIOD + value: "{{ .Values.env.resyncPeriod }}" + - name: DISABLE_TELEMETRY + value: "{{ .Values.disableTelemetry }}" + livenessProbe: + httpGet: + path: /healthz + port: health + readinessProbe: + httpGet: + path: /healthz + port: health + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- 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/charts/percona/psmdb-operator/1.16.3/templates/namespace.yaml b/charts/percona/psmdb-operator/1.16.3/templates/namespace.yaml new file mode 100644 index 000000000..cfc96d4d9 --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/templates/namespace.yaml @@ -0,0 +1,11 @@ +{{ if and .Values.watchNamespace .Values.createNamespace }} +{{ range ( split "," .Values.watchNamespace ) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ trim . }} + annotations: + helm.sh/resource-policy: keep +--- +{{ end }} +{{ end }} diff --git a/charts/percona/psmdb-operator/1.16.3/templates/role-binding.yaml b/charts/percona/psmdb-operator/1.16.3/templates/role-binding.yaml new file mode 100644 index 000000000..a815869d4 --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/templates/role-binding.yaml @@ -0,0 +1,41 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "psmdb-operator.fullname" . }} + namespace: {{ .Release.Namespace }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +--- +{{- end }} +{{- if .Values.rbac.create }} +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} +kind: ClusterRoleBinding +{{- else }} +kind: RoleBinding +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: service-account-{{ include "psmdb-operator.fullname" . }} +{{- if not (or .Values.watchNamespace .Values.watchAllNamespaces) }} + namespace: {{ .Release.Namespace }} +{{- end }} + labels: +{{ include "psmdb-operator.labels" . | indent 4 }} +subjects: +- kind: ServiceAccount + name: {{ include "psmdb-operator.fullname" . }} + {{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + namespace: {{ .Release.Namespace }} + {{- end }} +roleRef: + {{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + kind: ClusterRole + {{- else }} + kind: Role + {{- end }} + name: {{ include "psmdb-operator.fullname" . }} + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/charts/percona/psmdb-operator/1.16.3/templates/role.yaml b/charts/percona/psmdb-operator/1.16.3/templates/role.yaml new file mode 100644 index 000000000..537c1e86b --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/templates/role.yaml @@ -0,0 +1,166 @@ +{{- if .Values.rbac.create }} +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} +kind: ClusterRole +{{- else }} +kind: Role +{{- end }} +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "psmdb-operator.fullname" . }} +{{- if not (or .Values.watchNamespace .Values.watchAllNamespaces) }} + namespace: {{ .Release.Namespace }} +{{- end }} + labels: +{{ include "psmdb-operator.labels" . | indent 4 }} +rules: + - apiGroups: + - psmdb.percona.com + resources: + - perconaservermongodbs + - perconaservermongodbs/status + - perconaservermongodbs/finalizers + - perconaservermongodbbackups + - perconaservermongodbbackups/status + - perconaservermongodbbackups/finalizers + - perconaservermongodbrestores + - perconaservermongodbrestores/status + - perconaservermongodbrestores/finalizers + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +{{- if or .Values.watchNamespace .Values.watchAllNamespaces }} + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch +{{- end }} + - apiGroups: + - "" + resources: + - pods + - pods/exec + - services + - persistentvolumeclaims + - secrets + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - apps + resources: + - deployments + - replicasets + - statefulsets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - batch + resources: + - cronjobs + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - events.k8s.io + - "" + resources: + - events + verbs: + - get + - list + - watch + - create + - patch + - apiGroups: + - certmanager.k8s.io + - cert-manager.io + resources: + - issuers + - certificates + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - deletecollection + - apiGroups: + - net.gke.io + - multicluster.x-k8s.io + resources: + - serviceexports + - serviceimports + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - deletecollection +{{- end }} diff --git a/charts/percona/psmdb-operator/1.16.3/values.yaml b/charts/percona/psmdb-operator/1.16.3/values.yaml new file mode 100644 index 000000000..749d5413c --- /dev/null +++ b/charts/percona/psmdb-operator/1.16.3/values.yaml @@ -0,0 +1,99 @@ +# Default values for psmdb-operator. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: percona/percona-server-mongodb-operator + tag: 1.16.2 + pullPolicy: IfNotPresent + +# disableTelemetry: according to +# https://docs.percona.com/percona-operator-for-mongodb/telemetry.html +# this is how you can disable telemetry collection +# default is false which means telemetry will be collected +disableTelemetry: false + +# set if you want to specify a namespace to watch +# defaults to `.Release.namespace` if left blank +# multiple namespaces can be specified and separated by comma +# watchNamespace: +# set if you want that watched namespaces are created by helm +# createNamespace: false + +# set if operator should be deployed in cluster wide mode. defaults to false +watchAllNamespaces: false + +# rbac: settings for deployer RBAC creation +rbac: + # rbac.create: if false RBAC resources should be in place + create: true + +# serviceAccount: settings for Service Accounts used by the deployer +serviceAccount: + # serviceAccount.create: Whether to create the Service Accounts or not + create: true + # annotations to add to the service account + annotations: {} + +# annotations to add to the operator deployment +annotations: {} + +# labels to add to the operator deployment +labels: {} + +# annotations to add to the operator pod +podAnnotations: {} + # prometheus.io/scrape: "true" + # prometheus.io/port: "8080" + +# labels to the operator pod +podLabels: {} + +podSecurityContext: {} + # runAsNonRoot: true + # runAsUser: 2 + # runAsGroup: 2 + # fsGroup: 2 + # fsGroupChangePolicy: "OnRootMismatch" + +securityContext: {} + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + # seccompProfile: + # type: RuntimeDefault + +# set if you want to use a different operator name +# defaults to `percona-server-mongodb-operator` +# operatorName: + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +env: + resyncPeriod: 5s + +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 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +logStructured: false +logLevel: "INFO" diff --git a/charts/speedscale/speedscale-operator/2.2.203/.helmignore b/charts/speedscale/speedscale-operator/2.2.203/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/speedscale/speedscale-operator/2.2.203/Chart.yaml b/charts/speedscale/speedscale-operator/2.2.203/Chart.yaml new file mode 100644 index 000000000..eddb7f285 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/Chart.yaml @@ -0,0 +1,27 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Speedscale Operator + catalog.cattle.io/kube-version: '>= 1.17.0-0' + catalog.cattle.io/release-name: speedscale-operator +apiVersion: v1 +appVersion: 2.2.203 +description: Stress test your APIs with real world scenarios. Collect and replay + traffic without scripting. +home: https://speedscale.com +icon: file://assets/icons/speedscale-operator.png +keywords: +- speedscale +- test +- testing +- regression +- reliability +- load +- replay +- network +- traffic +kubeVersion: '>= 1.17.0-0' +maintainers: +- email: support@speedscale.com + name: Speedscale Support +name: speedscale-operator +version: 2.2.203 diff --git a/charts/speedscale/speedscale-operator/2.2.203/LICENSE b/charts/speedscale/speedscale-operator/2.2.203/LICENSE new file mode 100644 index 000000000..b78723d62 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2021 Speedscale + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/charts/speedscale/speedscale-operator/2.2.203/README.md b/charts/speedscale/speedscale-operator/2.2.203/README.md new file mode 100644 index 000000000..97a522e89 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/README.md @@ -0,0 +1,108 @@ +# Speedscale Operator + +The [Speedscale](https://www.speedscale.com) Operator is a [Kubernetes operator](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) +that watches for deployments to be applied to the cluster and takes action based on annotations. The operator +can inject a proxy to capture traffic into or out of applications, or setup an isolation test environment around +a deployment for testing. The operator itself is a deployment that will be always present on the cluster once +the helm chart is installed. + +## Prerequisites + +- Kubernetes 1.20+ +- Helm 3+ +- Appropriate [network and firewall configuration](https://docs.speedscale.com/reference/networking) for Speedscale cloud and webhook traffic + +## Get Repo Info + +```bash +helm repo add speedscale https://speedscale.github.io/operator-helm/ +helm repo update +``` + +_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Chart + +An API key is required. Sign up for a [free Speedscale trial](https://speedscale.com/free-trial/) if you do not have one. + +```bash +helm install speedscale-operator speedscale/speedscale-operator \ + -n speedscale \ + --create-namespace \ + --set apiKey= \ + --set clusterName= +``` + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +### Pre-install job failure + +We use pre-install job to check provided API key and provision some of the required resources. + +If the job failed during the installation, you'll see the following error during install: + +``` +Error: INSTALLATION FAILED: failed pre-install: job failed: BackoffLimitExceeded +``` + +You can inspect the logs using this command: + +```bash +kubectl -n speedscale logs job/speedscale-operator-pre-install +``` + +After fixing the error, uninstall the helm release, delete the failed job +and try installing again: + +```bash +helm -n speedscale uninstall speedscale-operator +kubectl -n speedscale delete job speedscale-operator-pre-install +``` + +## Uninstall Chart + +```bash +helm -n speedscale uninstall speedscale-operator +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +CRDs created by this chart are not removed by default and should be manually cleaned up: + +```bash +kubectl delete crd trafficreplays.speedscale.com +``` + +## Upgrading Chart + +```bash +helm repo update +helm -n speedscale upgrade speedscale-operator speedscale/speedscale-operator +``` + +Resources capturing traffic will need to be rolled to pick up the latest +Speedscale sidecar. Use the rollout restart command for each namespace and +resource type: + +```bash +kubectl -n rollout restart deployment +``` + +With Helm v3, CRDs created by this chart are not updated by default +and should be manually updated. +Consult also the [Helm Documentation on CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions). + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### Upgrading an existing Release to a new version + +A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an +incompatible breaking change needing manual actions. + + +## Help + +Speedscale docs information available at [docs.speedscale.com](https://docs.speedscale.com) or join us +on the [Speedscale community Slack](https://join.slack.com/t/speedscalecommunity/shared_invite/zt-x5rcrzn4-XHG1QqcHNXIM~4yozRrz8A)! diff --git a/charts/speedscale/speedscale-operator/2.2.203/app-readme.md b/charts/speedscale/speedscale-operator/2.2.203/app-readme.md new file mode 100644 index 000000000..97a522e89 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/app-readme.md @@ -0,0 +1,108 @@ +# Speedscale Operator + +The [Speedscale](https://www.speedscale.com) Operator is a [Kubernetes operator](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) +that watches for deployments to be applied to the cluster and takes action based on annotations. The operator +can inject a proxy to capture traffic into or out of applications, or setup an isolation test environment around +a deployment for testing. The operator itself is a deployment that will be always present on the cluster once +the helm chart is installed. + +## Prerequisites + +- Kubernetes 1.20+ +- Helm 3+ +- Appropriate [network and firewall configuration](https://docs.speedscale.com/reference/networking) for Speedscale cloud and webhook traffic + +## Get Repo Info + +```bash +helm repo add speedscale https://speedscale.github.io/operator-helm/ +helm repo update +``` + +_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Chart + +An API key is required. Sign up for a [free Speedscale trial](https://speedscale.com/free-trial/) if you do not have one. + +```bash +helm install speedscale-operator speedscale/speedscale-operator \ + -n speedscale \ + --create-namespace \ + --set apiKey= \ + --set clusterName= +``` + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +### Pre-install job failure + +We use pre-install job to check provided API key and provision some of the required resources. + +If the job failed during the installation, you'll see the following error during install: + +``` +Error: INSTALLATION FAILED: failed pre-install: job failed: BackoffLimitExceeded +``` + +You can inspect the logs using this command: + +```bash +kubectl -n speedscale logs job/speedscale-operator-pre-install +``` + +After fixing the error, uninstall the helm release, delete the failed job +and try installing again: + +```bash +helm -n speedscale uninstall speedscale-operator +kubectl -n speedscale delete job speedscale-operator-pre-install +``` + +## Uninstall Chart + +```bash +helm -n speedscale uninstall speedscale-operator +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +CRDs created by this chart are not removed by default and should be manually cleaned up: + +```bash +kubectl delete crd trafficreplays.speedscale.com +``` + +## Upgrading Chart + +```bash +helm repo update +helm -n speedscale upgrade speedscale-operator speedscale/speedscale-operator +``` + +Resources capturing traffic will need to be rolled to pick up the latest +Speedscale sidecar. Use the rollout restart command for each namespace and +resource type: + +```bash +kubectl -n rollout restart deployment +``` + +With Helm v3, CRDs created by this chart are not updated by default +and should be manually updated. +Consult also the [Helm Documentation on CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions). + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### Upgrading an existing Release to a new version + +A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an +incompatible breaking change needing manual actions. + + +## Help + +Speedscale docs information available at [docs.speedscale.com](https://docs.speedscale.com) or join us +on the [Speedscale community Slack](https://join.slack.com/t/speedscalecommunity/shared_invite/zt-x5rcrzn4-XHG1QqcHNXIM~4yozRrz8A)! diff --git a/charts/speedscale/speedscale-operator/2.2.203/questions.yaml b/charts/speedscale/speedscale-operator/2.2.203/questions.yaml new file mode 100644 index 000000000..29aee3895 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/questions.yaml @@ -0,0 +1,9 @@ +questions: +- variable: apiKey + default: "fffffffffffffffffffffffffffffffffffffffffffff" + description: "An API key is required to connect to the Speedscale cloud." + required: true + type: string + label: API Key + group: Authentication + diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/NOTES.txt b/charts/speedscale/speedscale-operator/2.2.203/templates/NOTES.txt new file mode 100644 index 000000000..cabb59b17 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/NOTES.txt @@ -0,0 +1,12 @@ +Thank you for installing the Speedscale Operator! + +Next you'll need to add the Speedscale Proxy Sidecar to your deployments. +See https://docs.speedscale.com/setup/sidecar/install/ + +If upgrading use the rollout restart command for each namespace and resource +type to ensure Speedscale sidecars are updated: + + kubectl -n rollout restart deployment + +Once your deployment is running the sidecar your service will show up on +https://app.speedscale.com/. diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/admission.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/admission.yaml new file mode 100644 index 000000000..9a2a943d3 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/admission.yaml @@ -0,0 +1,199 @@ +{{- $cacrt := "" -}} +{{- $crt := "" -}} +{{- $key := "" -}} +{{- $s := (lookup "v1" "Secret" .Release.Namespace "speedscale-webhook-certs") -}} +{{- if $s -}} +{{- $cacrt = index $s.data "ca.crt" | default (index $s.data "tls.crt") | b64dec -}} +{{- $crt = index $s.data "tls.crt" | b64dec -}} +{{- $key = index $s.data "tls.key" | b64dec -}} +{{ else }} +{{- $altNames := list ( printf "speedscale-operator.%s" .Release.Namespace ) ( printf "speedscale-operator.%s.svc" .Release.Namespace ) -}} +{{- $ca := genCA "speedscale-operator" 3650 -}} +{{- $cert := genSignedCert "speedscale-operator" nil $altNames 3650 $ca -}} +{{- $cacrt = $ca.Cert -}} +{{- $crt = $cert.Cert -}} +{{- $key = $cert.Key -}} +{{- end -}} +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + creationTimestamp: null + name: speedscale-operator + annotations: + argocd.argoproj.io/hook: PreSync + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + caBundle: {{ $cacrt | b64enc }} + service: + name: speedscale-operator + namespace: {{ .Release.Namespace }} + path: /mutate + failurePolicy: Ignore + name: sidecar.speedscale.com + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: "NotIn" + values: + - kube-system + - kube-node-lease + {{- if .Values.namespaceSelector }} + - key: kubernetes.io/metadata.name + operator: "In" + values: + {{- range .Values.namespaceSelector }} + - {{ . | quote }} + {{- end }} + {{- end }} + reinvocationPolicy: IfNeeded + rules: + - apiGroups: + - apps + - batch + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - deployments + - statefulsets + - daemonsets + - jobs + - replicasets + - apiGroups: + - "" + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - pods + sideEffects: None + timeoutSeconds: 10 +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + creationTimestamp: null + name: speedscale-operator-replay + annotations: + argocd.argoproj.io/hook: PreSync + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + caBundle: {{ $cacrt | b64enc }} + service: + name: speedscale-operator + namespace: {{ .Release.Namespace }} + path: /mutate-speedscale-com-v1-trafficreplay + failurePolicy: Fail + name: replay.speedscale.com + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: "NotIn" + values: + - kube-system + - kube-node-lease + {{- if .Values.namespaceSelector }} + - key: kubernetes.io/metadata.name + operator: "In" + values: + {{- range .Values.namespaceSelector }} + - {{ . | quote }} + {{- end }} + {{- end }} + rules: + - apiGroups: + - speedscale.com + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - trafficreplays + sideEffects: None + timeoutSeconds: 10 +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: speedscale-operator-replay + annotations: + argocd.argoproj.io/hook: PreSync + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + caBundle: {{ $cacrt | b64enc }} + service: + name: speedscale-operator + namespace: {{ .Release.Namespace }} + path: /validate-speedscale-com-v1-trafficreplay + failurePolicy: Fail + name: replay.speedscale.com + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: "NotIn" + values: + - kube-system + - kube-node-lease + {{- if .Values.namespaceSelector }} + - key: kubernetes.io/metadata.name + operator: "In" + values: + {{- range .Values.namespaceSelector }} + - {{ . | quote }} + {{- end }} + {{- end }} + rules: + - apiGroups: + - speedscale.com + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - trafficreplays + sideEffects: None + timeoutSeconds: 10 +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + helm.sh/hook: pre-install + helm.sh/hook-delete-policy: before-hook-creation + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} + creationTimestamp: null + name: speedscale-webhook-certs + namespace: {{ .Release.Namespace }} +type: kubernetes.io/tls +data: + ca.crt: {{ $cacrt | b64enc }} + tls.crt: {{ $crt | b64enc }} + tls.key: {{ $key | b64enc }} diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/configmap.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/configmap.yaml new file mode 100644 index 000000000..af735e288 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/configmap.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: speedscale-operator + namespace: {{ .Release.Namespace }} + annotations: + argocd.argoproj.io/hook: PreSync + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} +data: + CLUSTER_NAME: {{ .Values.clusterName }} + IMAGE_PULL_POLICY: {{ .Values.image.pullPolicy }} + IMAGE_PULL_SECRETS: "" + IMAGE_REGISTRY: {{ .Values.image.registry }} + IMAGE_TAG: {{ .Values.image.tag }} + INSTANCE_ID: '{{- $cm := (lookup "v1" "ConfigMap" .Release.Namespace "speedscale-operator") -}}{{ if $cm }}{{ $cm.data.INSTANCE_ID }}{{ else }}{{ ( printf "%s-%s" .Values.clusterName uuidv4 ) }}{{ end }}' + LOG_LEVEL: {{ .Values.logLevel }} + SPEEDSCALE_DLP_CONFIG: {{ .Values.dlp.config }} + SPEEDSCALE_FILTER_RULE: {{ .Values.filterRule }} + TELEMETRY_INTERVAL: 1s + WITH_DLP: {{ .Values.dlp.enabled | quote }} + WITH_INSPECTOR: {{ .Values.dashboardAccess | quote }} + API_KEY_SECRET_NAME: {{ .Values.apiKeySecret | quote }} + DEPLOY_DEMO: {{ .Values.deployDemo | quote }} + GLOBAL_ANNOTATIONS: {{ .Values.globalAnnotations | toJson | quote }} + GLOBAL_LABELS: {{ .Values.globalLabels | toJson | quote }} + {{- if .Values.http_proxy }} + HTTP_PROXY: {{ .Values.http_proxy }} + {{- end }} + {{- if .Values.https_proxy }} + HTTPS_PROXY: {{ .Values.https_proxy }} + {{- end }} + {{- if .Values.no_proxy }} + NO_PROXY: {{ .Values.no_proxy }} + {{- end }} + PRIVILEGED_SIDECARS: {{ .Values.privilegedSidecars | quote }} + DISABLE_SMARTDNS: {{ .Values.disableSidecarSmartReverseDNS | quote }} + SIDECAR_CONFIG: {{ .Values.sidecar | toJson | quote }} + FORWARDER_CONFIG: {{ .Values.forwarder | toJson | quote }} diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/crds/trafficreplays.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/crds/trafficreplays.yaml new file mode 100644 index 000000000..9a85d5da4 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/crds/trafficreplays.yaml @@ -0,0 +1,514 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.15.0 + creationTimestamp: null + name: trafficreplays.speedscale.com +spec: + group: speedscale.com + names: + kind: TrafficReplay + listKind: TrafficReplayList + plural: trafficreplays + shortNames: + - replay + singular: trafficreplay + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.active + name: Active + type: boolean + - jsonPath: .spec.mode + name: Mode + type: string + - jsonPath: .status.conditions[-1:].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: TrafficReplay is the Schema for the trafficreplays API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TrafficReplaySpec defines the desired state of TrafficReplay + properties: + buildTag: + description: |- + BuildTag links a unique tag, build hash, etc. to the generated + traffic replay report. That way you can connect the report results to the + version of the code that was tested. + type: string + cleanup: + description: |- + Cleanup is the name of cleanup mode used for this + TrafficReplay. + enum: + - inventory + - all + - none + type: string + collectLogs: + description: |- + CollectLogs enables or disables log collection from target + workload. Defaults to true. + DEPRECATED: use TestReport.ActualConfig.Cluster.CollectLogs + type: boolean + configChecksum: + description: |- + ConfigChecksum, managed my the operator, is the SHA1 checksum of the + configuration. + type: string + customURL: + description: CustomURL allows to specify custom URL to the SUT. + type: string + generatorLowData: + description: |- + GeneratorLowData forces the generator into a high + efficiency/low data output mode. This is ideal for high volume + performance tests. Defaults to false. + DEPRECATED + type: boolean + mode: + description: Mode is the name of replay mode used for this TrafficReplay. + enum: + - full-replay + - responder-only + - generator-only + type: string + needsReport: + description: Indicates whether a responder-only replay needs a report. + type: boolean + proxyMode: + description: |- + ProxyMode defines proxy operational mode used with injected sidecar. + DEPRECATED + type: string + responderLowData: + description: |- + ResponderLowData forces the responder into a high + efficiency/low data output mode. This is ideal for high volume + performance tests. Defaults to false. + DEPRECATED + type: boolean + secretRefs: + description: |- + SecretRefs hold the references to the secrets which contain + various secrets like (e.g. short-lived JWTs to be used by the generator + for authorization with HTTP calls). + items: + description: |- + LocalObjectReference contains enough information to locate the referenced + Kubernetes resource object. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + type: array + sidecar: + description: |- + Sidecar defines sidecar specific configuration. + DEPRECATED: use Workloads + properties: + inject: + description: 'DEPRECATED: do not use' + type: boolean + patch: + description: Patch is .yaml file patch for the Workload + format: byte + type: string + tls: + properties: + in: + description: In provides configuration for sidecar inbound + TLS. + properties: + private: + description: Private is the filename of the TLS inbound + private key. + type: string + public: + description: Public is the filename of the TLS inbound + public key. + type: string + secret: + description: Secret is a secret with the TLS keys to use + for inbound traffic. + type: string + type: object + mutual: + description: Mutual provides configuration for sidecar mutual + TLS. + properties: + private: + description: Private is the filename of the mutual TLS + private key. + type: string + public: + description: Public is the filename of the mutual TLS + public key. + type: string + secret: + description: Secret is a secret with the mutual TLS keys. + type: string + type: object + out: + description: |- + Out enables or disables TLS out on the + sidecar during replay. + type: boolean + type: object + type: object + snapshotID: + description: |- + SnapshotID is the id of the traffic snapshot for this + TrafficReplay. + type: string + testConfigID: + description: |- + TestConfigID is the id of the replay configuration to be used + by the generator and responder for the TrafficReplay. + type: string + timeout: + description: |- + Timeout is the time to wait for replay test to finish. Defaults + to value of the `TIMEOUT` setting of the operator. + type: string + ttlAfterReady: + description: |- + TTLAfterReady provides a TTL (time to live) mechanism to limit + the lifetime of TrafficReplay object that have finished the execution and + reached its final state (either complete or failed). + type: string + workloadRef: + description: |- + WorkloadRef is the reference to the target workload (SUT) for + TrafficReplay. The operations will be performed in the namespace of the + target object. + DEPRECATED: use Workloads + properties: + apiVersion: + description: API version of the referenced object. + type: string + kind: + description: Kind of the referenced object. Defaults to "Deployment". + type: string + name: + description: Name of the referenced object. + type: string + namespace: + description: Namespace of the referenced object. Defaults to the + TrafficReplay namespace. + type: string + required: + - name + type: object + workloads: + description: |- + Workloads define target workloads (SUT) for a TrafficReplay. Many + workloads may be provided, or none. Workloads may be modified and + restarted during replay to configure communication with a responder. + items: + description: |- + Workload represents a Kubernetes workload to be targeted during replay and + associated settings. + properties: + customURI: + description: CustomURI will be target of the traffic instead + of directly targeting workload + type: string + inTrafficKey: + description: 'DEPRECATED: use InTrafficKeys' + type: string + inTrafficKeys: + description: 'DEPRECATED: use Tests' + items: + type: string + type: array + mocks: + description: |- + Mocks are strings used to identify slices of outbound snapshot traffic to + mock for this workload and maps directly to a snapshot's `OutTraffic` + field. Snapshot egress traffic can be split across multiple slices where + each slice contains part of the traffic. A workload may specify multiple + keys and multiple workloads may specify the same key. + + + Only the traffic slices defined here will be mocked. A workload with no + keys defined will not mock any traffic. Pass '*' to mock all traffic. + + + Mock strings may only match part of the snapshot's `OutTraffic` key if the + string matches exactly one key. For example, the test string + `foo.example.com` would match the `OutTraffic` key of + my-service:foo.example.com:8080, as long as no other keys would match + `foo.example.com`. Multiple mocks must be specified for multiple keys + unless using '*'. + items: + type: string + type: array + outTrafficKeys: + description: 'DEPRECATED: use Mocks' + items: + type: string + type: array + ref: + description: |- + Ref is a reference to a cluster workload, like a deployment or a + statefulset. + properties: + apiVersion: + description: API version of the referenced object. + type: string + kind: + description: Kind of the referenced object. Defaults to + "Deployment". + type: string + name: + description: Name of the referenced object. + type: string + namespace: + description: Namespace of the referenced object. Defaults + to the TrafficReplay namespace. + type: string + required: + - name + type: object + routing: + description: Routing configures how workloads route egress traffic + to responders + enum: + - hostalias + - nat + type: string + sidecar: + description: |- + TODO: this is not implemented, come back and replace deprecated Sidecar with workload specific settings + Sidecar defines sidecar specific configuration. + properties: + inject: + description: 'DEPRECATED: do not use' + type: boolean + patch: + description: Patch is .yaml file patch for the Workload + format: byte + type: string + tls: + properties: + in: + description: In provides configuration for sidecar inbound + TLS. + properties: + private: + description: Private is the filename of the TLS + inbound private key. + type: string + public: + description: Public is the filename of the TLS inbound + public key. + type: string + secret: + description: Secret is a secret with the TLS keys + to use for inbound traffic. + type: string + type: object + mutual: + description: Mutual provides configuration for sidecar + mutual TLS. + properties: + private: + description: Private is the filename of the mutual + TLS private key. + type: string + public: + description: Public is the filename of the mutual + TLS public key. + type: string + secret: + description: Secret is a secret with the mutual + TLS keys. + type: string + type: object + out: + description: |- + Out enables or disables TLS out on the + sidecar during replay. + type: boolean + type: object + type: object + tests: + description: |- + Tests are strings used to identify slices of inbound snapshot traffic this + workload is targeting and maps directly to a snapshot's `InTraffic` field. + Snapshot ingress traffic can be split across multiple slices where each + slice contains part of the traffic. A key must only be specified once + across all workloads, but a workload may specify multiple keys. + + + Test strings may only match part of the snapshot's `InTraffic` key if the + string matches exactly one key. For example, the test string + `foo.example.com` would match the `InTraffic` key of + my-service:foo.example.com:8080, as long as no other keys would match + `foo.example.com` + + + This field is optional in the spec to provide support for single-workload + and legacy replays, but must be specified for multi-workload replays in + order to provide deterministic replay configuration. + items: + type: string + type: array + type: object + type: array + required: + - snapshotID + - testConfigID + type: object + status: + default: + observedGeneration: -1 + description: TrafficReplayStatus defines the observed state of TrafficReplay + properties: + active: + description: Active indicates whether this traffic replay is currently + underway or not. + type: boolean + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + finishedTime: + description: Information when the traffic replay has finished. + format: date-time + type: string + initializedTime: + description: Information when the test environment was successfully + prepared. + format: date-time + type: string + lastHeartbeatTime: + description: 'DEPRECATED: will not be set' + format: date-time + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + reconcileFailures: + description: |- + ReconcileFailures is the number of times the traffic replay controller + experienced an error during the reconciliation process. The traffic + replay will be deleted if too many errors occur. + format: int64 + type: integer + reportID: + description: The id of the traffic replay report created. + type: string + reportURL: + description: The url to the traffic replay report. + type: string + startedTime: + description: Information when the traffic replay has started. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: null + storedVersions: null diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/deployments.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/deployments.yaml new file mode 100644 index 000000000..e5f329257 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/deployments.yaml @@ -0,0 +1,132 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + operator.speedscale.com/ignore: "true" + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} + labels: + app: speedscale-operator + controlplane.speedscale.com/component: operator + {{- if .Values.globalLabels }} +{{ toYaml .Values.globalLabels | indent 4}} + {{- end }} + name: speedscale-operator + namespace: {{ .Release.Namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: speedscale-operator + controlplane.speedscale.com/component: operator + strategy: + type: Recreate + template: + metadata: + annotations: + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 8}} + {{- end }} + labels: + app: speedscale-operator + controlplane.speedscale.com/component: operator + {{- if .Values.globalLabels }} +{{ toYaml .Values.globalLabels | indent 8}} + {{- end }} + spec: + containers: + - command: + - /operator + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + envFrom: + - configMapRef: + name: speedscale-operator + # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#container-v1-core + # When a key exists in multiple sources, the value associated with the last source will take precedence. + # Values defined by an Env with a duplicate key will take precedence. + - configMapRef: + name: speedscale-operator-override + optional: true + - secretRef: + name: '{{ ne .Values.apiKeySecret "" | ternary .Values.apiKeySecret "speedscale-apikey" }}' + optional: false + image: '{{ .Values.image.registry }}/operator:{{ .Values.image.tag }}' + imagePullPolicy: {{ .Values.image.pullPolicy }} + livenessProbe: + failureThreshold: 5 + httpGet: + path: /healthz + port: health-check + scheme: HTTP + initialDelaySeconds: 30 + periodSeconds: 30 + successThreshold: 1 + timeoutSeconds: 5 + name: operator + ports: + - containerPort: 443 + name: webhook-server + - containerPort: 8081 + name: health-check + readinessProbe: + failureThreshold: 10 + httpGet: + path: /readyz + port: health-check + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 5 + successThreshold: 1 + timeoutSeconds: 5 + resources: {{- toYaml .Values.operator.resources | nindent 10 }} + securityContext: + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: true + runAsNonRoot: false + # Run as root to bind 443 https://github.com/kubernetes/kubernetes/issues/56374 + runAsUser: 0 + volumeMounts: + - mountPath: /tmp + name: tmp + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: webhook-certs + readOnly: true + - mountPath: /etc/ssl/speedscale + name: speedscale-tls-out + readOnly: true + hostNetwork: {{ .Values.hostNetwork }} + securityContext: + runAsNonRoot: true + serviceAccountName: speedscale-operator + terminationGracePeriodSeconds: 10 + volumes: + - emptyDir: {} + name: tmp + - name: webhook-certs + secret: + secretName: speedscale-webhook-certs + - name: speedscale-tls-out + secret: + secretName: speedscale-certs + {{- if .Values.affinity }} + affinity: {{ toYaml .Values.affinity | nindent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: {{ toYaml .Values.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{ toYaml .Values.nodeSelector | nindent 8 }} + {{- end }} diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/hooks.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/hooks.yaml new file mode 100644 index 000000000..3e8231f19 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/hooks.yaml @@ -0,0 +1,73 @@ +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + helm.sh/hook: pre-install + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "4" + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} + creationTimestamp: null + name: speedscale-operator-pre-install + namespace: {{ .Release.Namespace }} + labels: + {{- if .Values.globalLabels }} +{{ toYaml .Values.globalLabels | indent 4}} + {{- end }} +spec: + backoffLimit: 0 + ttlSecondsAfterFinished: 30 + template: + metadata: + annotations: + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 8}} + {{- end }} + creationTimestamp: null + labels: + {{- if .Values.globalLabels }} +{{ toYaml .Values.globalLabels | indent 8}} + {{- end }} + spec: + containers: + - args: + - |- + # ensure valid settings before the chart reports a successfull install + {{- if .Values.http_proxy }} + HTTP_PROXY={{ .Values.http_proxy | quote }} \ + {{- end }} + {{- if .Values.https_proxy }} + HTTPS_PROXY={{ .Values.https_proxy | quote }} \ + {{- end }} + {{- if .Values.no_proxy }} + NO_PROXY={{ .Values.no_proxy | quote }} \ + {{- end }} + speedctl init --overwrite --no-rcfile-update \ + --api-key $SPEEDSCALE_API_KEY \ + --app-url $SPEEDSCALE_APP_URL + + # in case we're in istio + curl -X POST http://127.0.0.1:15000/quitquitquit || true + command: + - sh + - -c + envFrom: + - secretRef: + name: '{{ ne .Values.apiKeySecret "" | ternary .Values.apiKeySecret "speedscale-apikey" }}' + optional: false + image: '{{ .Values.image.registry }}/speedscale-cli:{{ .Values.image.tag }}' + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: speedscale-cli + resources: {} + restartPolicy: Never + {{- if .Values.affinity }} + affinity: {{ toYaml .Values.affinity | nindent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: {{ toYaml .Values.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{ toYaml .Values.nodeSelector | nindent 8 }} + {{- end }} diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/rbac.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/rbac.yaml new file mode 100644 index 000000000..e1ea42d99 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/rbac.yaml @@ -0,0 +1,244 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + name: speedscale-operator + {{- if .Values.globalAnnotations }} + annotations: {{ toYaml .Values.globalAnnotations | nindent 4 }} + {{- end }} +rules: +- apiGroups: + - apps + resources: + - deployments + - statefulsets + - daemonsets + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + resources: + - replicasets + verbs: + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + verbs: + - get + - list +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + - clusterroles + verbs: + - get + - list +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - configmaps + - secrets + - pods + - services + - serviceaccounts + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - pods/log + verbs: + - get + - list +- apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch +- apiGroups: + - metrics.k8s.io + resources: + - pods + verbs: + - get + - list + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + - roles + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - networking.istio.io + resources: + - envoyfilters + - sidecars + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - security.istio.io + resources: + - peerauthentications + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - speedscale.com + resources: + - trafficreplays + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - speedscale.com + resources: + - trafficreplays/status + verbs: + - get + - update + - patch +- apiGroups: + - argoproj.io + resources: + - rollouts + verbs: + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: speedscale-operator + {{- if .Values.globalAnnotations }} + annotations: {{ toYaml .Values.globalAnnotations | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: speedscale-operator +subjects: +- kind: ServiceAccount + name: speedscale-operator + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +automountServiceAccountToken: true +kind: ServiceAccount +metadata: + creationTimestamp: null + labels: + app: speedscale-operator + controlplane.speedscale.com/component: operator + name: speedscale-operator + namespace: {{ .Release.Namespace }} + {{- if .Values.globalAnnotations }} + annotations: {{ toYaml .Values.globalAnnotations | nindent 4 }} + {{- end }} diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/secrets.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/secrets.yaml new file mode 100644 index 000000000..1fb6999e4 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/secrets.yaml @@ -0,0 +1,18 @@ +--- +{{ if .Values.apiKey }} +apiVersion: v1 +kind: Secret +metadata: + name: speedscale-apikey + namespace: {{ .Release.Namespace }} + annotations: + helm.sh/hook: pre-install + helm.sh/hook-weight: "3" + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} +type: Opaque +data: + SPEEDSCALE_API_KEY: {{ .Values.apiKey | b64enc }} + SPEEDSCALE_APP_URL: {{ .Values.appUrl | b64enc }} +{{ end }} diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/services.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/services.yaml new file mode 100644 index 000000000..f9da2c25c --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/services.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: null + labels: + app: speedscale-operator + controlplane.speedscale.com/component: operator + name: speedscale-operator + namespace: {{ .Release.Namespace }} + {{- if .Values.globalAnnotations }} + annotations: {{ toYaml .Values.globalAnnotations | nindent 4 }} + {{- end }} +spec: + ports: + - port: 443 + protocol: TCP + selector: + app: speedscale-operator + controlplane.speedscale.com/component: operator +status: + loadBalancer: {} diff --git a/charts/speedscale/speedscale-operator/2.2.203/templates/tls.yaml b/charts/speedscale/speedscale-operator/2.2.203/templates/tls.yaml new file mode 100644 index 000000000..4a2456288 --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/templates/tls.yaml @@ -0,0 +1,183 @@ +{{- $crt := "" -}} +{{- $key := "" -}} +{{- $s := (lookup "v1" "Secret" .Release.Namespace "speedscale-certs") -}} +{{- if $s -}} +{{- $crt = index $s.data "tls.crt" | b64dec -}} +{{- $key = index $s.data "tls.key" | b64dec -}} +{{ else }} +{{- $cert := genCA "Speedscale" 3650 -}} +{{- $crt = $cert.Cert -}} +{{- $key = $cert.Key -}} +{{- end -}} +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + helm.sh/hook: pre-install + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "5" + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} + creationTimestamp: null + name: speedscale-operator-create-jks + namespace: {{ .Release.Namespace }} + labels: + {{- if .Values.globalLabels }} +{{ toYaml .Values.globalLabels | indent 4}} + {{- end }} +spec: + backoffLimit: 0 + ttlSecondsAfterFinished: 30 + template: + metadata: + annotations: + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 8}} + {{- end }} + creationTimestamp: null + labels: + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 8}} + {{- end }} + spec: + containers: + - args: + - |- + keytool -keystore /usr/lib/jvm/jre/lib/security/cacerts -importcert -noprompt -trustcacerts -storepass changeit -alias speedscale -file /etc/ssl/speedscale/tls.crt + kubectl -n ${POD_NAMESPACE} delete secret speedscale-jks || true + kubectl -n ${POD_NAMESPACE} create secret generic speedscale-jks --from-file=cacerts.jks=/usr/lib/jvm/jre/lib/security/cacerts + + # in case we're in istio + curl -X POST http://127.0.0.1:15000/quitquitquit || true + command: + - sh + - -c + volumeMounts: + - mountPath: /etc/ssl/speedscale + name: speedscale-tls-out + readOnly: true + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + envFrom: + - secretRef: + name: '{{ ne .Values.apiKeySecret "" | ternary .Values.apiKeySecret "speedscale-apikey" }}' + optional: false + image: '{{ .Values.image.registry }}/amazoncorretto' + imagePullPolicy: {{ .Values.image.pullPolicy }} + name: create-jks + resources: {} + restartPolicy: Never + serviceAccountName: speedscale-operator-provisioning + volumes: + - name: speedscale-tls-out + secret: + secretName: speedscale-certs + {{- if .Values.affinity }} + affinity: {{ toYaml .Values.affinity | nindent 8 }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: {{ toYaml .Values.tolerations | nindent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{ toYaml .Values.nodeSelector | nindent 8 }} + {{- end }} +--- +apiVersion: v1 +automountServiceAccountToken: true +kind: ServiceAccount +metadata: + annotations: + helm.sh/hook: pre-install + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "1" + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} + creationTimestamp: null + labels: + app: speedscale-operator + controlplane.speedscale.com/component: operator + name: speedscale-operator-provisioning + namespace: {{ .Release.Namespace }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + helm.sh/hook: pre-install + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "2" + creationTimestamp: null + name: speedscale-operator-provisioning +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + - validatingwebhookconfigurations + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + helm.sh/hook: pre-install + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + helm.sh/hook-weight: "3" + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} + creationTimestamp: null + name: speedscale-operator-provisioning +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: speedscale-operator-provisioning +subjects: +- kind: ServiceAccount + name: speedscale-operator-provisioning + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: Secret +metadata: + annotations: + helm.sh/hook: pre-install + helm.sh/hook-delete-policy: before-hook-creation + {{- if .Values.globalAnnotations }} +{{ toYaml .Values.globalAnnotations | indent 4}} + {{- end }} + creationTimestamp: null + name: speedscale-certs + namespace: {{ .Release.Namespace }} +type: kubernetes.io/tls +data: + tls.crt: {{ $crt | b64enc }} + tls.key: {{ $key | b64enc }} diff --git a/charts/speedscale/speedscale-operator/2.2.203/values.yaml b/charts/speedscale/speedscale-operator/2.2.203/values.yaml new file mode 100644 index 000000000..7448263bb --- /dev/null +++ b/charts/speedscale/speedscale-operator/2.2.203/values.yaml @@ -0,0 +1,133 @@ +# An API key is required to connect to the Speedscale cloud. +# If you need a key email support@speedscale.com. +apiKey: "" + +# A secret name can be referenced instead of the api key itself. +# The secret must be of the format: +# +# type: Opaque +# data: +# SPEEDSCALE_API_KEY: +# SPEEDSCALE_APP_URL: +apiKeySecret: "" + +# Speedscale domain to use. +appUrl: "app.speedscale.com" + +# The name of your cluster. +clusterName: "my-cluster" + +# Speedscale components image settings. +image: + registry: gcr.io/speedscale + tag: v2.2.203 + pullPolicy: Always + +# Log level for Speedscale components. +logLevel: "info" + +# Namespaces to be watched by Speedscale Operator as a list of names. +namespaceSelector: [] + +# Instructs operator to deploy resources necessary to interact with your cluster from the Speedscale dashboard. +dashboardAccess: true + +# Filter Rule to apply to the Speedscale Forwarder +filterRule: "standard" + +# Data Loss Prevention settings. +dlp: + # Instructs operator to enable data loss prevention features + enabled: false + + # Configuration for data loss prevention + config: "standard" + +# If the operator pod/webhooks need to be on the host network. +# This is only needed if the control plane cannot connect directly to a pod +# for eg. if Calico is used as EKS's default networking +# https://docs.tigera.io/calico/3.25/getting-started/kubernetes/managed-public-cloud/eks#install-eks-with-calico-networking +hostNetwork: false + +# A set of annotations to be applied to all Speedscale related deployments, +# services, jobs, pods, etc. +# +# Example: +# annotation.first: value +# annotation.second: value +globalAnnotations: {} + +# A set of labels to be applied to all Speedscale related deployments, +# services, jobs, pods, etc. +# +# Example: +# label1: value +# label2: value +globalLabels: {} + +# A full affinity object as detailed: https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity +affinity: {} + +# The list of tolerations as detailed: https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/ +tolerations: [] + +# A nodeselector object as detailed: https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/ +nodeSelector: {} + +# Deploy a demo app at startup. Set this to an empty string to not deploy. +# Valid values: ["java", ""] +deployDemo: "java" + +# Proxy connection settings if required by your network. These translate to standard proxy environment +# variables HTTP_PROXY, HTTPS_PROXY, and NO_PROXY +http_proxy: "" +https_proxy: "" +no_proxy: "" + +# control if sidecar init containers should run with privileged set +privilegedSidecars: false + +# control if the sidecar should enable/disable use of the smart dns lookup feature (requires NET_ADMIN) +disableSidecarSmartReverseDNS: false + +# Operator settings. These limits are recommended unless you have a cluster +# with a very large number of workloads (for eg. 10k+ deployments, replicasets, etc.). +operator: + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + +# Default sidecar settings. Example: +# sidecar: +# resources: +# limits: +# cpu: 500m +# memory: 512Mi +# ephemeral-storage: 100Mi +# requests: +# cpu: 10m +# memory: 32Mi +# ephemeral-storage: 100Mi +# ignore_src_hosts: example.com, example.org +# ignore_src_ips: 8.8.8.8, 1.1.1.1 +# ignore_dst_hosts: example.com, example.org +# ignore_dst_ips: 8.8.8.8, 1.1.1.1 +# insert_init_first: false +# tls_out: false +# reinitialize_iptables: false +sidecar: {} + +# Forwarder settings +# forwarder: +# resources: +# limits: +# cpu: 500m +# memory: 500M +# requests: +# cpu: 300m +# memory: 250M +forwarder: {} diff --git a/index.yaml b/index.yaml index f762f7ef1..5d832c2ff 100644 --- a/index.yaml +++ b/index.yaml @@ -3668,6 +3668,38 @@ entries: - assets/cerbos/cerbos-0.37.0.tgz version: 0.37.0 cf-runtime: + - annotations: + artifacthub.io/changes: | + - kind: security + description: "cf-docker-builder image upgraded to 1.3.13 with security fixes" + artifacthub.io/containsSecurityUpdates: "false" + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Codefresh + catalog.cattle.io/kube-version: '>=1.18-0' + catalog.cattle.io/release-name: cf-runtime + apiVersion: v2 + created: "2024-07-24T00:47:54.844278145Z" + dependencies: + - name: cf-common + repository: file://./charts/cf-common + version: 0.16.0 + description: A Helm chart for Codefresh Runner + digest: 6cb1a48345b42dca5df076a2e96db2c42657a7f029004270ab7a47006d903216 + home: https://codefresh.io/ + icon: file://assets/icons/cf-runtime.png + keywords: + - codefresh + - runner + kubeVersion: '>=1.18-0' + maintainers: + - name: codefresh + url: https://codefresh-io.github.io/ + name: cf-runtime + sources: + - https://github.com/codefresh-io/venona + urls: + - assets/codefresh/cf-runtime-6.3.52.tgz + version: 6.3.52 - annotations: artifacthub.io/changes: | - kind: changed @@ -19368,6 +19400,36 @@ entries: - assets/avesha/kubeslice-worker-1.1.1.tgz version: 1.1.1 kuma: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Kuma + catalog.cattle.io/namespace: kuma-system + catalog.cattle.io/release-name: kuma + apiVersion: v2 + appVersion: 2.8.2 + created: "2024-07-24T00:47:57.264963587Z" + description: A Helm chart for the Kuma Control Plane + digest: d03cbb6a2ad31eca4fc9f8fed7ec4e78e9cff0114eafdd6d4f28da025ae3b7c3 + home: https://github.com/kumahq/kuma + icon: file://assets/icons/kuma.svg + keywords: + - service mesh + - control plane + maintainers: + - email: jakub.dyszkiewicz@konghq.com + name: Jakub Dyszkiewicz + url: https://github.com/jakubdyszkiewicz + - email: charly.molter@konghq.com + name: Charly Molter + url: https://github.com/lahabana + - email: michael.beaumont@konghq.com + name: Mike Beaumont + url: https://github.com/michaelbeaumont + name: kuma + type: application + urls: + - assets/kuma/kuma-2.8.2.tgz + version: 2.8.2 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Kuma @@ -22326,6 +22388,33 @@ entries: - assets/airlock/microgateway-cni-4.2.3.tgz version: 4.2.3 minio-operator: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Minio Operator + catalog.cattle.io/kube-version: '>=1.19-0' + catalog.cattle.io/release-name: minio-operator + apiVersion: v2 + appVersion: v6.0.1 + created: "2024-07-24T00:47:57.431219038Z" + description: A Helm chart for MinIO Operator + digest: 68f82232a13b78fffc97505f3184f4aa90d65b4a32589c70ee81cf20bd61980c + home: https://min.io + icon: file://assets/icons/minio-operator.png + keywords: + - storage + - object-storage + - S3 + kubeVersion: '>=1.19-0' + maintainers: + - email: dev@minio.io + name: MinIO, Inc + name: minio-operator + sources: + - https://github.com/minio/operator + type: application + urls: + - assets/minio/minio-operator-6.0.1.tgz + version: 6.0.1 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Minio Operator @@ -23401,6 +23490,95 @@ entries: - assets/f5/nginx-ingress-1.0.2.tgz version: 1.0.2 nri-bundle: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: New Relic + catalog.cattle.io/release-name: nri-bundle + apiVersion: v2 + created: "2024-07-24T00:47:58.015351885Z" + dependencies: + - condition: infrastructure.enabled,newrelic-infrastructure.enabled + name: newrelic-infrastructure + repository: file://./charts/newrelic-infrastructure + version: 3.34.2 + - condition: prometheus.enabled,nri-prometheus.enabled + name: nri-prometheus + repository: file://./charts/nri-prometheus + version: 2.1.18 + - condition: newrelic-prometheus-agent.enabled + name: newrelic-prometheus-agent + repository: file://./charts/newrelic-prometheus-agent + version: 1.14.2 + - condition: webhook.enabled,nri-metadata-injection.enabled + name: nri-metadata-injection + repository: file://./charts/nri-metadata-injection + version: 4.20.2 + - condition: metrics-adapter.enabled,newrelic-k8s-metrics-adapter.enabled + name: newrelic-k8s-metrics-adapter + repository: file://./charts/newrelic-k8s-metrics-adapter + version: 1.11.0 + - condition: ksm.enabled,kube-state-metrics.enabled + name: kube-state-metrics + repository: file://./charts/kube-state-metrics + version: 5.12.1 + - condition: kubeEvents.enabled,nri-kube-events.enabled + name: nri-kube-events + repository: file://./charts/nri-kube-events + version: 3.10.1 + - condition: logging.enabled,newrelic-logging.enabled + name: newrelic-logging + repository: file://./charts/newrelic-logging + version: 1.22.3 + - condition: newrelic-pixie.enabled + name: newrelic-pixie + repository: file://./charts/newrelic-pixie + version: 2.1.4 + - condition: k8s-agents-operator.enabled + name: k8s-agents-operator + repository: file://./charts/k8s-agents-operator + version: 0.10.0 + - alias: pixie-chart + condition: pixie-chart.enabled + name: pixie-operator-chart + repository: file://./charts/pixie-operator-chart + version: 0.1.6 + - condition: newrelic-infra-operator.enabled + name: newrelic-infra-operator + repository: file://./charts/newrelic-infra-operator + version: 2.11.0 + description: Groups together the individual charts for the New Relic Kubernetes + solution for a more comfortable deployment. + digest: be07bd7740c50e8296284497e8ec76c9e40d276fb71fdf27d812c6540c501fa9 + home: https://github.com/newrelic/helm-charts + icon: file://assets/icons/nri-bundle.svg + keywords: + - infrastructure + - newrelic + - monitoring + maintainers: + - name: juanjjaramillo + url: https://github.com/juanjjaramillo + - name: csongnr + url: https://github.com/csongnr + - name: dbudziwojskiNR + url: https://github.com/dbudziwojskiNR + name: nri-bundle + sources: + - https://github.com/newrelic/nri-bundle/ + - https://github.com/newrelic/nri-bundle/tree/master/charts/nri-bundle + - https://github.com/newrelic/nri-kubernetes/tree/master/charts/newrelic-infrastructure + - https://github.com/newrelic/nri-prometheus/tree/master/charts/nri-prometheus + - https://github.com/newrelic/newrelic-prometheus-configurator/tree/master/charts/newrelic-prometheus-agent + - https://github.com/newrelic/k8s-metadata-injection/tree/master/charts/nri-metadata-injection + - https://github.com/newrelic/newrelic-k8s-metrics-adapter/tree/master/charts/newrelic-k8s-metrics-adapter + - https://github.com/newrelic/nri-kube-events/tree/master/charts/nri-kube-events + - https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging + - https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-pixie + - https://github.com/newrelic/newrelic-infra-operator/tree/master/charts/newrelic-infra-operator + - https://github.com/newrelic/k8s-agents-operator/tree/master/charts/k8s-agents-operator + urls: + - assets/new-relic/nri-bundle-5.0.87.tgz + version: 5.0.87 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: New Relic @@ -27188,6 +27366,29 @@ entries: - assets/fairwinds/polaris-5.11.1.tgz version: 5.11.1 psmdb-db: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Percona Server for MongoDB + catalog.cattle.io/kube-version: '>=1.21-0' + catalog.cattle.io/release-name: psmdb-db + apiVersion: v2 + appVersion: 1.16.2 + created: "2024-07-24T00:47:58.126917877Z" + description: A Helm chart for installing Percona Server MongoDB Cluster Databases + using the PSMDB Operator. + digest: f092caea88f186bc3bbe7cba2005c68fd914b9b40a7acd75f31f61a9661bb232 + home: https://www.percona.com/doc/kubernetes-operator-for-psmongodb/index.html + icon: file://assets/icons/psmdb-db.png + kubeVersion: '>=1.21-0' + maintainers: + - email: tomislav.plavcic@percona.com + name: tplavcic + - email: natalia.marukovich@percona.com + name: nmarukovich + name: psmdb-db + urls: + - assets/percona/psmdb-db-1.16.3.tgz + version: 1.16.3 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Percona Server for MongoDB @@ -27343,6 +27544,30 @@ entries: - assets/percona/psmdb-db-1.14.4.tgz version: 1.14.4 psmdb-operator: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Percona Operator for MongoDB + catalog.cattle.io/kube-version: '>=1.21-0' + catalog.cattle.io/release-name: psmdb-operator + apiVersion: v2 + appVersion: 1.16.2 + created: "2024-07-24T00:47:58.145580985Z" + description: A Helm chart for deploying the Percona Operator for MongoDB + digest: 9e40a7a9b9964dea7aaa2d157f800409406495be42d298f676af64d1f965537f + home: https://docs.percona.com/percona-operator-for-mongodb/ + icon: file://assets/icons/psmdb-operator.png + kubeVersion: '>=1.21-0' + maintainers: + - email: tomislav.plavcic@percona.com + name: tplavcic + - email: natalia.marukovich@percona.com + name: nmarukovich + - email: sergey.pronin@percona.com + name: spron-in + name: psmdb-operator + urls: + - assets/percona/psmdb-operator-1.16.3.tgz + version: 1.16.3 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Percona Operator for MongoDB @@ -31070,6 +31295,37 @@ entries: - assets/btp/sextant-2.2.21.tgz version: 2.2.21 speedscale-operator: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Speedscale Operator + catalog.cattle.io/kube-version: '>= 1.17.0-0' + catalog.cattle.io/release-name: speedscale-operator + apiVersion: v1 + appVersion: 2.2.203 + created: "2024-07-24T00:47:58.548755049Z" + description: Stress test your APIs with real world scenarios. Collect and replay + traffic without scripting. + digest: 1c9b7d4ee215dbb7f538e75262cef74855bfe19e020363d8e47f6a6dcc730c3e + home: https://speedscale.com + icon: file://assets/icons/speedscale-operator.png + keywords: + - speedscale + - test + - testing + - regression + - reliability + - load + - replay + - network + - traffic + kubeVersion: '>= 1.17.0-0' + maintainers: + - email: support@speedscale.com + name: Speedscale Support + name: speedscale-operator + urls: + - assets/speedscale/speedscale-operator-2.2.203.tgz + version: 2.2.203 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Speedscale Operator @@ -35208,6 +35464,33 @@ entries: - assets/triggermesh/triggermesh-0.8.3.tgz version: 0.8.3 vals-operator: + - annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: Vals-Operator + catalog.cattle.io/kube-version: '>= 1.19.0-0' + catalog.cattle.io/release-name: vals-operator + apiVersion: v2 + appVersion: v0.7.10 + created: "2024-07-24T00:47:54.98959224Z" + description: 'This helm chart installs the Digitalis Vals Operator to manage and + sync secrets from supported backends into Kubernetes. ## About Vals-Operator + Here at [Digitalis](https://digitalis.io) we love [vals](https://github.com/helmfile/vals), + it''s a tool we use daily to keep secrets stored securely. Inspired by this + tool, we have created an operator to manage Kubernetes secrets. *vals-operator* + syncs secrets from any secrets store supported by [vals](https://github.com/helmfile/vals) + into Kubernetes. Also, `vals-operator` supports database secrets as provider + by [HashiCorp Vault Secret Engine](https://developer.hashicorp.com/vault/docs/secrets/databases). ' + digest: 0ca4c66bee8b3afc964c1adbcd8dc1e9770b3f2515b5a58827ee64f82fd0351e + icon: file://assets/icons/vals-operator.png + kubeVersion: '>= 1.19.0-0' + maintainers: + - email: info@digitalis.io + name: Digitalis.IO + name: vals-operator + type: application + urls: + - assets/digitalis/vals-operator-0.7.10.tgz + version: 0.7.10 - annotations: catalog.cattle.io/certified: partner catalog.cattle.io/display-name: Vals-Operator @@ -36651,4 +36934,4 @@ entries: urls: - assets/netfoundry/ziti-host-1.5.1.tgz version: 1.5.1 -generated: "2024-07-22T00:49:16.88535433Z" +generated: "2024-07-24T00:47:54.476524979Z"

Z}=u>!%!p~L@U!l-Wmb|1?)Ji@?J$U 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