From e7abe463f89fd4a8aeb1d98ba64eb0b29b256080 Mon Sep 17 00:00:00 2001 From: shawnj Date: Fri, 13 May 2022 06:33:21 -0700 Subject: [PATCH] Make charts - NewRelic --- assets/newrelic/nri-bundle-4.3.200.tgz | Bin 0 -> 199373 bytes .../newrelic/nri-bundle/4.3.200/.helmignore | 22 + charts/newrelic/nri-bundle/4.3.200/Chart.lock | 33 + charts/newrelic/nri-bundle/4.3.200/Chart.yaml | 77 + charts/newrelic/nri-bundle/4.3.200/README.md | 138 + .../nri-bundle/4.3.200/README.md.gotmpl | 100 + .../newrelic/nri-bundle/4.3.200/app-readme.md | 5 + .../charts/kube-state-metrics/.helmignore | 21 + .../charts/kube-state-metrics/Chart.yaml | 18 + .../4.3.200/charts/kube-state-metrics/LICENSE | 202 + .../4.3.200/charts/kube-state-metrics/OWNERS | 6 + .../charts/kube-state-metrics/README.md | 66 + .../kube-state-metrics/templates/NOTES.txt | 10 + .../kube-state-metrics/templates/_helpers.tpl | 47 + .../templates/clusterrolebinding.yaml | 23 + .../templates/deployment.yaml | 216 + .../templates/kubeconfig-secret.yaml | 15 + .../kube-state-metrics/templates/pdb.yaml | 20 + .../templates/podsecuritypolicy.yaml | 42 + .../templates/psp-clusterrole.yaml | 22 + .../templates/psp-clusterrolebinding.yaml | 19 + .../kube-state-metrics/templates/role.yaml | 192 + .../templates/rolebinding.yaml | 27 + .../kube-state-metrics/templates/service.yaml | 42 + .../templates/serviceaccount.yaml | 18 + .../templates/servicemonitor.yaml | 34 + .../templates/stsdiscovery-role.yaml | 29 + .../templates/stsdiscovery-rolebinding.yaml | 20 + .../charts/kube-state-metrics/values.yaml | 179 + .../newrelic-infra-operator/.helmignore | 1 + .../charts/newrelic-infra-operator/Chart.yaml | 19 + .../charts/newrelic-infra-operator/README.md | 142 + .../ci/test-values.yaml | 39 + .../templates/NOTES.txt | 4 + .../templates/_helpers.tpl | 148 + .../job-patch/clusterrole.yaml | 25 + .../job-patch/clusterrolebinding.yaml | 20 + .../job-patch/job-createSecret.yaml | 54 + .../job-patch/job-patchWebhook.yaml | 54 + .../admission-webhooks/job-patch/psp.yaml | 50 + .../admission-webhooks/job-patch/role.yaml | 21 + .../job-patch/rolebinding.yaml | 21 + .../job-patch/serviceaccount.yaml | 13 + .../mutatingWebhookConfiguration.yaml | 32 + .../templates/cert-manager.yaml | 52 + .../templates/clusterrole.yaml | 52 + .../templates/clusterrolebinding.yaml | 26 + .../templates/configmap.yaml | 35 + .../templates/deployment.yaml | 90 + .../templates/secret.yaml | 13 + .../templates/service.yaml | 13 + .../templates/serviceaccount.yaml | 7 + .../newrelic-infra-operator/values.yaml | 190 + .../newrelic-infrastructure/.helmignore | 1 + .../charts/newrelic-infrastructure/Chart.lock | 6 + .../charts/newrelic-infrastructure/Chart.yaml | 36 + .../charts/newrelic-infrastructure/README.md | 209 + .../newrelic-infrastructure/README.md.gotmpl | 139 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 25 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 25 + .../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 | 85 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 55 + .../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 | 199 + .../templates/clusterrole.yaml | 33 + .../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 | 8 + .../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 | 202 + .../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/_naming.tpl | 8 + .../templates/ksm/_tolerations_helper.tpl | 11 + .../templates/ksm/agent-configmap.yaml | 18 + .../templates/ksm/deployment.yaml | 191 + .../templates/ksm/scraper-configmap.yaml | 16 + .../templates/kubelet/_affinity_helper.tpl | 33 + .../kubelet/_agent-config_helper.tpl | 31 + .../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 | 245 + .../kubelet/integrations-configmap.yaml | 37 + .../templates/kubelet/scraper-configmap.yaml | 18 + .../templates/podsecuritypolicy.yaml | 26 + .../templates/secret.yaml | 2 + .../templates/serviceaccount.yaml | 13 + .../newrelic-infrastructure/values.yaml | 514 ++ .../newrelic-k8s-metrics-adapter/.helmignore | 25 + .../newrelic-k8s-metrics-adapter/Chart.lock | 6 + .../newrelic-k8s-metrics-adapter/Chart.yaml | 26 + .../newrelic-k8s-metrics-adapter/README.md | 143 + .../README.md.gotmpl | 109 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 25 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 25 + .../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 | 85 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 55 + .../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 | 49 + .../templates/_helpers.tpl | 49 + .../templates/adapter-clusterrolebinding.yaml | 14 + .../templates/adapter-rolebinding.yaml | 15 + .../templates/apiservice/apiservice.yaml | 19 + .../apiservice/job-patch/clusterrole.yaml | 24 + .../job-patch/clusterrolebinding.yaml | 19 + .../job-patch/job-createSecret.yaml | 52 + .../job-patch/job-patchAPIService.yaml | 50 + .../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 | 17 + .../templates/configmap.yaml | 18 + .../templates/deployment.yaml | 114 + .../templates/hpa-clusterrole.yaml | 15 + .../templates/hpa-clusterrolebinding.yaml | 14 + .../templates/secret.yaml | 10 + .../templates/service.yaml | 13 + .../templates/serviceaccount.yaml | 7 + .../tests/apiservice_test.yaml | 18 + .../tests/common_extra_naming_test.yaml | 24 + .../tests/configmap_test.yaml | 92 + .../tests/deployment_test.yaml | 68 + .../tests/hpa_clusterrolebinding_test.yaml | 12 + .../job_patch_cluster_rolebinding_test.yaml | 16 + .../tests/job_patch_clusterrole_test.yaml | 12 + .../tests/job_patch_common_test.yaml | 22 + .../job_patch_job_createsecret_test.yaml | 31 + .../job_patch_job_patchapiservice_test.yaml | 34 + .../newrelic-k8s-metrics-adapter/values.yaml | 148 + .../charts/newrelic-logging/Chart.yaml | 19 + .../4.3.200/charts/newrelic-logging/README.md | 216 + .../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 .../charts/newrelic-logging/k8s/README.md | 63 + .../newrelic-logging/k8s/fluent-conf.yml | 69 + .../k8s/new-relic-fluent-plugin.yml | 70 + .../charts/newrelic-logging/k8s/rbac.yml | 31 + .../newrelic-logging/templates/NOTES.txt | 18 + .../newrelic-logging/templates/_helpers.tpl | 185 + .../templates/clusterrole.yaml | 23 + .../templates/clusterrolebinding.yaml | 15 + .../newrelic-logging/templates/configmap.yaml | 26 + .../templates/daemonset-windows.yaml | 142 + .../newrelic-logging/templates/daemonset.yaml | 146 + .../templates/podsecuritypolicy.yaml | 25 + .../newrelic-logging/templates/secret.yaml | 12 + .../templates/serviceaccount.yaml | 16 + .../charts/newrelic-logging/values.yaml | 235 + .../4.3.200/charts/newrelic-pixie/Chart.yaml | 20 + .../4.3.200/charts/newrelic-pixie/README.md | 78 + .../charts/newrelic-pixie/ci/test-values.yaml | 5 + .../charts/newrelic-pixie/templates/NOTES.txt | 27 + .../newrelic-pixie/templates/_helpers.tpl | 154 + .../newrelic-pixie/templates/deployment.yaml | 111 + .../newrelic-pixie/templates/secret.yaml | 20 + .../4.3.200/charts/newrelic-pixie/values.yaml | 48 + .../4.3.200/charts/nri-kube-events/Chart.lock | 6 + .../4.3.200/charts/nri-kube-events/Chart.yaml | 36 + .../4.3.200/charts/nri-kube-events/README.md | 82 + .../charts/nri-kube-events/README.md.gotmpl | 43 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 25 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 25 + .../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 | 85 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 55 + .../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-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 | 7 + .../nri-kube-events/templates/_helpers.tpl | 45 + .../templates/_helpers_compatibility.tpl | 10 + .../templates/agent-configmap.yaml | 12 + .../templates/clusterrole.yaml | 12 + .../templates/clusterrolebinding.yaml | 16 + .../nri-kube-events/templates/configmap.yaml | 20 + .../nri-kube-events/templates/deployment.yaml | 121 + .../nri-kube-events/templates/secret.yaml | 2 + .../templates/serviceaccount.yaml | 11 + .../tests/agent_configmap_test.yaml | 38 + .../nri-kube-events/tests/configmap_test.yaml | 60 + .../tests/deployment_test.yaml | 76 + .../tests/security_context_test.yaml | 71 + .../charts/nri-kube-events/values.yaml | 117 + .../charts/nri-metadata-injection/.helmignore | 1 + .../charts/nri-metadata-injection/Chart.lock | 6 + .../charts/nri-metadata-injection/Chart.yaml | 35 + .../charts/nri-metadata-injection/README.md | 71 + .../nri-metadata-injection/README.md.gotmpl | 43 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 25 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 25 + .../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 | 85 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 55 + .../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 | 64 + .../job-patch/clusterrole.yaml | 25 + .../job-patch/clusterrolebinding.yaml | 20 + .../job-patch/job-createSecret.yaml | 54 + .../job-patch/job-patchWebhook.yaml | 54 + .../admission-webhooks/job-patch/psp.yaml | 50 + .../admission-webhooks/job-patch/role.yaml | 21 + .../job-patch/rolebinding.yaml | 21 + .../job-patch/serviceaccount.yaml | 13 + .../mutatingWebhookConfiguration.yaml | 37 + .../templates/cert-manager.yaml | 53 + .../templates/deployment.yaml | 80 + .../templates/service.yaml | 13 + .../tests/cluster_test.yaml | 20 + .../tests/image_test.yaml | 61 + .../tests/volume_mounts_test.yaml | 30 + .../charts/nri-metadata-injection/values.yaml | 94 + .../4.3.200/charts/nri-prometheus/.helmignore | 22 + .../4.3.200/charts/nri-prometheus/Chart.lock | 6 + .../4.3.200/charts/nri-prometheus/Chart.yaml | 35 + .../4.3.200/charts/nri-prometheus/README.md | 118 + .../charts/nri-prometheus/README.md.gotmpl | 85 + .../charts/common-library/.helmignore | 23 + .../charts/common-library/Chart.yaml | 25 + .../common-library/templates/_affinity.tpl | 10 + .../templates/_agent-config.tpl | 25 + .../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 | 85 + .../common-library/templates/_labels.tpl | 54 + .../common-library/templates/_license.tpl | 55 + .../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 | 82 + .../nri-prometheus/tests/deployment_test.yaml | 83 + .../nri-prometheus/tests/labels_test.yaml | 32 + .../4.3.200/charts/nri-prometheus/values.yaml | 250 + .../charts/pixie-operator-chart/Chart.yaml | 4 + .../pixie-operator-chart/crds/olm_crd.yaml | 7130 +++++++++++++++++ .../pixie-operator-chart/crds/vizier_crd.yaml | 264 + .../templates/00_olm.yaml | 197 + .../templates/01_px_olm.yaml | 11 + .../templates/02_catalog.yaml | 13 + .../templates/03_subscription.yaml | 11 + .../templates/04_vizier.yaml | 85 + .../templates/deleter.yaml | 25 + .../templates/deleter_role.yaml | 55 + .../charts/pixie-operator-chart/values.yaml | 69 + .../nri-bundle/4.3.200/ci/test-values.yaml | 21 + .../nri-bundle/4.3.200/questions.yaml | 113 + .../newrelic/nri-bundle/4.3.200/values.yaml | 159 + index.yaml | 82 + 371 files changed, 23737 insertions(+) create mode 100644 assets/newrelic/nri-bundle-4.3.200.tgz create mode 100644 charts/newrelic/nri-bundle/4.3.200/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/Chart.lock create mode 100644 charts/newrelic/nri-bundle/4.3.200/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/README.md.gotmpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/app-readme.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/LICENSE create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/OWNERS create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/NOTES.txt create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/deployment.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/kubeconfig-secret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/pdb.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/podsecuritypolicy.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/psp-clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/role.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/rolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/service.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/servicemonitor.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/stsdiscovery-role.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/ci/test-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/NOTES.txt create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-createSecret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-patchWebhook.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/psp.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/role.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/rolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/mutatingWebhookConfiguration.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/cert-manager.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/deployment.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/secret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/service.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/Chart.lock create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/README.md.gotmpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_affinity.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_cluster.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_images.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_labels.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_license.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_naming.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_privileged.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_proxy.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_security-context.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_staging.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/ci/test-cplane-kind-deployment-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/ci/test-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/NOTES.txt create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/_helpers_compatibility.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_affinity_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_agent-config_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_host_network.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_naming.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_rbac.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_tolerations_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/agent-configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/daemonset.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/rolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/scraper-configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_affinity_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_agent-config_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_naming.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_tolerations_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/agent-configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/deployment.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/scraper-configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_affinity_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_agent-config_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_naming.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_security_context_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_tolerations_helper.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/agent-configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/daemonset.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/integrations-configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/scraper-configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/podsecuritypolicy.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/secret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/Chart.lock create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/README.md.gotmpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_affinity.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_cluster.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_images.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_labels.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_naming.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_privileged.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_proxy.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_security-context.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_staging.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/ci/test-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/adapter-clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/adapter-rolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/apiservice.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-createSecret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-patchAPIService.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/psp.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/role.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/rolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/deployment.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/secret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/service.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/apiservice_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/common_extra_naming_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/configmap_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/deployment_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/hpa_clusterrolebinding_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_cluster_rolebinding_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_clusterrole_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_common_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_createsecret_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_patchapiservice_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-enable-windows-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-lowdatamode-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-override-global-lowdatamode.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-staging-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-with-empty-global.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-with-empty-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/k8s/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/k8s/fluent-conf.yml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/k8s/new-relic-fluent-plugin.yml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/k8s/rbac.yml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/NOTES.txt create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/daemonset-windows.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/daemonset.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/podsecuritypolicy.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/secret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/templates/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-pixie/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-pixie/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-pixie/ci/test-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-pixie/templates/NOTES.txt create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-pixie/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-pixie/templates/deployment.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-pixie/templates/secret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/newrelic-pixie/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/Chart.lock create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/README.md.gotmpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_affinity.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_cluster.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_images.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_labels.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_license.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_naming.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_privileged.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_proxy.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_security-context.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_staging.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/charts/common-library/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/ci/test-custom-attributes-as-map.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/ci/test-custom-attributes-as-string.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/ci/test-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/NOTES.txt create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/_helpers_compatibility.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/agent-configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/deployment.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/secret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/templates/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/tests/agent_configmap_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/tests/configmap_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/tests/deployment_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/tests/security_context_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-kube-events/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/Chart.lock create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/README.md.gotmpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_affinity.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_cluster.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_images.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_labels.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_license.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_naming.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_privileged.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_proxy.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_security-context.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_staging.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/charts/common-library/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/ci/test-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/NOTES.txt create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-createSecret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/job-patchWebhook.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/psp.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/role.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/rolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/job-patch/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/admission-webhooks/mutatingWebhookConfiguration.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/cert-manager.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/deployment.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/templates/service.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/tests/cluster_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/tests/image_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/tests/volume_mounts_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-metadata-injection/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/Chart.lock create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/README.md create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/README.md.gotmpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/.helmignore create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_affinity.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_agent-config.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_cluster.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_custom-attributes.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_dnsconfig.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_fedramp.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_hostnetwork.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_images.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_labels.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_license.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_license_secret.yaml.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_low-data-mode.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_naming.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_nodeselector.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_priority-class-name.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_privileged.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_proxy.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_security-context.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_serviceaccount.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_staging.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_tolerations.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/templates/_verbose-log.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/charts/common-library/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/ci/test-lowdatamode-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/ci/test-override-global-lowdatamode.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/ci/test-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/static/lowdatamodedefaults.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/templates/_helpers.tpl create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/templates/clusterrole.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/templates/clusterrolebinding.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/templates/configmap.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/templates/deployment.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/templates/secret.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/templates/serviceaccount.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/tests/configmap_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/tests/deployment_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/tests/labels_test.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/nri-prometheus/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/Chart.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/crds/olm_crd.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/crds/vizier_crd.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/templates/00_olm.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/templates/01_px_olm.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/templates/02_catalog.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/templates/03_subscription.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/templates/04_vizier.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/templates/deleter.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/templates/deleter_role.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/charts/pixie-operator-chart/values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/ci/test-values.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/questions.yaml create mode 100644 charts/newrelic/nri-bundle/4.3.200/values.yaml diff --git a/assets/newrelic/nri-bundle-4.3.200.tgz b/assets/newrelic/nri-bundle-4.3.200.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a03840adeab2b7ef6864af210dee4b862d631e98 GIT binary patch literal 199373 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

gD(eCGUT6Yab#h%- zR?*Oy@!4VpZ)qeRg>W`Zy1xXMrt#PT4(id@HtIN=wcve_A1=cj*Xw|pf3_}UdtS^i z4Hi6MV5`{rwKBrjfNd~*8?MFkpHPIWvFIQpHbmRa5YZVO0r)MQj#c8kXLxo3L~QI< zwGc$ymW2pJl(%8fG=N}g{zhYVp30$6{kkD#oGkQ%(*2z?QWj=M=JZj%oHIAEYleO8 zA#z&`9RCxUkVrB8F^niMKBFI;V`4tduAubZ--4|&#~B;8J<9@A2IYHaU3$b{&xP{r zF50l&EQLZ0GWI}E=fKbYEtvCqTuwswaO$`B6>}>_e%CTG?IDrAL?2N(q$ckw2k68T zF8)Ye7YxEmm@;fTXQ#&^pBgrt&_LSZ3OT?La)cpd%X(D{Lddo66*1sYjcMkZ8zeg| zh1+C6L$@~=L~Jnil>gyq-+;#9`X0cyY9U`1TP5JvCEKY{jxa zs*jjQQ?8VwlGus-cO@W%Yke5Y+$@zvA11ZZzIhc z5q6<8#W%}=CqQ$>~C|v7o!`i7k2_lvUI}{9Z?n|IhCG{rht3h_c;qZ8TfxZmLpBPp=*`jn9`} zx54DXdT9iH+NW}TeuV%hP;HX@?qUN+c`dr6N8v%b+cGk$d-1ycfwON=9e@SNn1jRG zrs*@KBKY_pq_iZJ^uwLs*9zX=CF|SD?l53S^9-0u&TlN;R=O&hxBU4*VrfMc`2$y0!i5p&}`^T9J_Lo$Y zB+g8<)_g21k`u(d`zSme0mPHvg?D|cAxQzev@>@<)6wcO%h`mk!n1D#a6HY2fVUIu6e6G9>x>j_+@>aV@wmZmEKiR#I5M=-G;iCIbufWOOo#PKpXZRS>8!KpzzvWZqSCdg$F0`Y(X8L05-uiBb zPl2QCivV<%Zd-7IOFp)uVr6jcMftI-1U%5{+zV%jXI`!Osp1LEnW)QTo<8qD+%nQJ zEuDgrhIMJ(^e4=9SRq~YF(O^3I;M)1u&055Q@fpB7}KC!0PtP08j{s7CR)|h6~-UR zcD|e7mpJsFf4)w3az9!8{k$FDPZs<-`F*`SJ%5ebZ8zUeZa#0!{9h+=h1uH&`ae8x z3A*2#^$810A+85ek#E2AWFEb*P}JhIz9n}p>k!cPSs%^EyQi_C)@!GQ)@iOj$1YZe zY_8?aHz73|%Jgfgpn>1-gvmz^fpcC8))b`!5vXEy*ZWu~PTctZ@E}3u=MJw{!AaK@ zLCE*!iDP%b?H2*S8U8J~&Rf`TA0&wlG}W$0LKXV~Hk3y0Z(Qx}ozSmukJps&Z<<6;V2rv>!TM~OGXQE_Lh z%SPwrvB7UQLQ@HlcMewdFS%;Uv8f&~%))6M&$Ml<)j`nIWTFr{yc>+r-0hG_Nx|Dx zV$ue>)o8~^!Up>js9l-@`svSZF+ha@<)*;Z1>ufLu5b+lXT#`Kb&gI$TSEz;Z+Z3(%E{ntbSy)x9~NRLFQMxXeH!Q6@`N!a z?+0bHu;=j*rcdbS^7Fos)Nf&!rUikKb{hy>(J?h5Q&`Bm&zQbgnUl*u?VQ*zon72Ff{IE7*>+Z=Jj_D@P=;NsNxjj zVeY5flgyYKH1%PZ!d{h_vzpudul+U#$U)t&?b>5nbAWUNiyNZGAR+fJnjNQ8*SdYf z7y!~h{py588KBo=mytkk2Di2JOsX2PlCcNthisP#Z9^3-Ya(cIWp**r1G5>=Tp94a zpC+NGwD~v7Q>67k`O`@s3HdG7-U6jG=Mqg;ULoFOcqa99scdO Y5%h+{$D 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%0AtrUy>LaWw_DNIRG89{)ycX>|aZecw@dfczi5v3; zX1c@b9vz932NaS*z!`ISY2eO~xMPs>{ubpPUEV#^+DHPQ#*@;NXa7Aqq#UALh&4eG zrhWvf2-PJqL`UON_QOlmwzpRvJG=Rpdvy8!V{Lrur?TkK#T5w37?ssIG8Nugegcq6D)a|Cf>8JmQGxs$Xnw2Cq|L^ zc?Ig?R0G!KaU#7b^5;e!~0XATs%N)5Qq7qQ|Alttymo;nz3a2F?;;$b_dgSF^c_d6-=_}69&(v89uYr+ev+)kf?8}olmRv)7Ep)FXSxgh zkbE&1QA=@{mOjaXoh-N=o8i$~ta?@@zuKM6Mf|_H6cvEeLaBhe?as#L*7nYef46YYaY?`IZ<)=Z zu!)6|Xum)}>Mtv8blydM#(JMGzsaIhmxBEtQb<4AB-g}`_zV&NOxXXO&c=4u{$p#i zv)KRhC@H(SPA2~U3yA+85MM}Wlo&zsg;>k{rbl}r4sSDYn@#CO3C^i_;g*rzu5GvM zPDPS|h!vZg2zeOo1BIfHjRj*#ry3}UQf|E2q(YV(zned+J)i{kX6{QW7Ij4qgJ?)b zgs)3+X5ATwltCPgy+*35hci7aklFI!u#t6Ay?V8EGs!cE|24go4jr z>Yo1|bFLmc#w7WFV{;>S{&yDg|6Iy^j(0jBJnAAo#GS3}Zl~jJZ97|Jdvn9x+$R6V z?d_edjjheCe{VT>`^82FxB8oI@5N@PRZNKQe*xG#YuU4nqYBd&2q^eBb|4&Zl-cDBr5y^v}p->5%UZwI=i3L0W*zm`;c*};)fy+FOKhL z3_5z9K*Ujo*~CTI<4o#!vkFSfOg98Wf+ahLOf{6JY-i*PWWD|k<))QMQv{0zy0nxi>P?Pf@wp`MYly~uXwF|g&Bep-g=*eXe{l+Y!ZBXRk#pyFbu z6W*D2f7o{s$gbR4LjOl=j+;$%MhLnzc;}_eaRgf4WSD{^dd5~rCpwzcKQik}WpYRc zlt#Kadkw3wi7}9N{ftvE;A!&0aE+;l zd!9xo9-yn_Jz**HXs}d};d?3d$S}Eu751Oj!03Lgtgvt9LL$XVmmI$**sf5DG}s=1!#SH2D~C)#Si^F5?2GEcV8bAuYP1B@QYa8j6ztmN3z{3gk%0+Of%^h&v%4C-$oT; z9vexAatNMP=1yqfdkGDU6foIx)IZTv0|n4*N^RLWD4g#!i`O6;76c)Gg(HQS&liB; zyAb3!p}{NVg4-gGFaTs;l;@F|AV@LD9U&(fFw%Wl&!Be9QOQwIf@0a4$?1$q|n4)O0WD14h_gn%K2V3x{+GNLoaheza4A=eC+ z7|VdGz}7{HoJhbkLHHG`N)IJQu}`yyCkyHEX=Rwd&Wo3azO6VytIH-lN#CC=3Z} zSG6`_v_mht0|#X*0LXSFTgJP^*pF@vCfrFzO*7MW)tR=f#ki7+T{1*IWGO~C%hGVX zlLjeSe|0|W$GE5^?wf!0NSMgKRNFe z?SJ<7|2uhH(6VLxjQz$4Acp<^?BdPKH-8_Zk$ydrkvUTWni%hCo)xWsfO2VoYu&i#|l-rBvRrdANW;Why{sN*44+!#Q}x1EhVtKPFfm)aA*-_ZDi(oAYQN;=VY zA?b!&@r_!~JtMn;q4%KNdWIxvcoRlsMgpZMf@__(>h%jY!6Ig~`koRT{2E6qPMV*> zh_DsQ$fATu<)dCPSQh<28z;_?f?^@NlDfJp8b>Qx89(4%F_PYp^hzB!ieLCSZ-~C@ z_4-~J@SP%?QKugmoXYOVr{?n2&nEl-mCaKdrGX~-|Lo-4+5b;_=X?2oCyy0d3&SQ9 z(wJ`*a1xHl3{O@lKNbkl86ps0$MjaP-7rIZeW5vKs6%6dqA(^Mkk!@EJHg`CLtRdz zln94v{OCN~XnfB}`kRG1sz9M{DDY9mD$EV|@4s$zs6ZT#0+|G?|IVg@X5 z(%K}bY5kv`y8b_d)4?A9cPEc?{)c-c-@fVTR>A9vZSOTsEQH<0@Jnjztc<@@7o9_8 z7E#Jw*j#gl7QlW>VzmGFzZz6myS;&7vcFnHLv&x#i8`61(38(!VX)5nmv;myjmTQ& zfQ{?F=brxuy^}ru>rNh5|2M`HWjEn0d-#Nx*_@`~e+0to^>+|eEN2K}f?Uvud@d}( zOP7%_y6PgFgnv)zGGRmXzSH?bS`ul?n)e+sqdl8)i+jAWfd)VamkWX}JHLY8&@ z_+lbF);}Ar|8W=xoY<|{K-2m^KXcdr$w_apU;n#!KGypGK}?X(hYiq($kmn7Iz_Hb8F4{3}tBI9aF6fl=tF_ku+LFI`8rFZme_YW2pA63T z>wg!|7b4hiB+^S=1)r=#bl(-hN|m8pAzqL;`bc{@9q>o{uflts&j>u!;sjMF&HAjP z5sCJik)hyp@gfeuN?v$g4UdihBxg=pHvF#F>mS|pk9d!bY;vQ1(@5;{NT0G^%dXK- zShyceLVVtbo&8gI*5Ut~1^}<;|NY+S$%)JV&(8MeznwgrNAg}%25QH;x3kMwhVKOq zU17m)a4{z&Tt$XLwFU!JF|i*KG`xwx7IEt%gS#OrEi->3K%PyvJg-9#C%+LXuR1!P z8=QRYvHh+p-Z)%TR2C&1b^MgX0ZEN`;~n%^T)B4=>m@(k+flcf32S|TI?~|Tjxt&w z&b+iA6(J0r?zAzsFm`X}`)183hE2~!7uQ$J=zjgIm9&Ka<-~`d7nE{x+C(?)I?HK} z%7Ui5G1IMr>;URc2+s8gZ{3euWmOJA*)a5v8>2wCi!53ZTeN+2(KZdi=?qk2QXcOd zqRtUc5_vK_G6Zh^sTtP!)`|Rw~acwEYG@+SCRK`eBnAiugjOb3)VNi0cNt1;dNGJMd|KoEu%Wyn;D6 zKpoePqhr@k;+yjM_U7W{v#VDxpTBr>`N9d0kE&yzqlWnBs5acZ-tvSozt6PSb!n`5 zR2Of)yevC(eRaow{l|-oim{U$%6?oIhbk z7KJ$p3$>B{$=bwk-XXW#ZKuQCx`hJ(;6H|`bX70QQMMvlWV4q+NrvXrK*2xMnuI0Z zqkQLGPhfWmYIy!xl~qS#f52(MsoZb`wCb)5!oIz#l|Q9bZ+Qgvww0Q`wY8JjbnJ!w zs^bn~ecQFSt(7nL!CkZUpIXOL_pGD;+cW@t)BSJ%eBkv-^Xlg?@sR|4 zlSl>lnxF|z!KzZ=a!9}miPED2+iA1OmIA3BB`6E8hnkajC`W)Wu~B?nYmc=`q$xbHm;-L z{_mvUKQ6@oKi}W~?c{k>z>oI+=lwq{6y`h}O}Lo(Y#x#*fSal@4rb&?ChkJot`QCg zNB^5;tB5?EMmX!Te=l)L4$%L+f97J$H&l?P??Up%Iy`Sv2zl?xlb`8=BzQ)KPoAK^ zemXGuzj@vx(FvJcprU#Iq)UhJgilat7KO$ugo8jw9|KYtuzxb17KtJeQj32A$T4R+7vcD2 z(?VK+K7@jn$t=YILEWy7(&aEjw}$Q%PzAaI*v1T$ql05z!gULJP6Oh3#=L5SwEnks zGc-f9Hx^k6&i*&(%0Fa`EF9w*2{fRJ=e^5kVz@{mvJik^bAsOMHTNx((9&W&<#A)P zSt>Ih*;v&F0!Y+b5F9h@oi?X2O&P-IHVg<#aXf=VjdmW!aiAl2$p&T=Ehx(jevz{j z=6l|+i3DrnRmk{W!fh-kik2MmP??8LSl2^4Ea{<+4#}HDvpGqbaB%~KUAUZff{A(W zmyD#}G6a#pG;*(XpleUzaYV=U6wU>L1K*eto+kqG-lKP`grIvQJ*D9<9o+-nd-o7g zO#G|2Bb!p`VpD zUxm5Y2K7`Fsr1J+4DBHxkx+>PwTAA|n9_(>BoNEc{dOSSL}d=Rd&y*Ig%S^i8A|)I zR&NWp6Y7%a&BizsAXWK9-V6xbs6kqKw5exJ{A{xlvl$y!RSr6CR$|z|p?e{S$Y|mB zTL8?4nk0yCDZg(5`V|G#G2pFZ|3j7QO#eb;1yO<_4%TyqhoX>*>J-Fd`6By-n3T}G zf@x`cew)z1S7p4~WGX>8S6RSAq@pe0?}}!)*U=>t>|>xP%gX78vSsvDVzfe!P2b0S zZ2;OkC-mAN_@Yq5)Y6?nO|bt^fURS0;_vG~?3Wb3PWPLk^F;+=eBHRyZVxFvuhTIW zDt2ijOmm}r=_*z!VQqrH4#k^T(C$|Iksza?-W<%fQULp;7`!rC_v<{mrRP0C@2!B9 zrJ4>a#R1P_N2x5$WG8`KIzVM<2K^P%+7T&BGuTNWS00P9G)Mj!QtJ?urHS=dNL!3I zS(>Ss404NzlchPtr-RSwQfvRTe%84E^Jg?$tcUz6o`(DX9Id(3jGm@DIagBd|4F2D||4+iBjId0t+x)_%i&?i77)+D> z-{8!R|8R1?xBuJCBe(=u=NYju`^STm)3fvMzVG4jBp}nO-=4-A86q)B#4oQH5ux5Or)8(E0DTdoHlsr~UfhJPv%*`M)=C@t^yH zef*c*JRfWQ8v#kT5{(q%Gw{;Z)Y_-Dkw`a@QgW0w=?L@k$06$X`<@6=P2(YY@mn52 z*^Yx;j9P4ecLMNQ&ItV>>g2yVp67ay+Bia#4N(-v%MYICxO+;+aK!X*xum7au~Fv5x1NPMo|6&n&0TRNM>)KQ6gsAWIA5*~?i> z_3IZO$Yhy^DYuKlTUy2_Qh>bTTLU%VOmRG4sW1pDm};@Po(OXL#dkn81K) zlpSd05Ow;U{T8`@w)V8~|6`eq{cxobV6XVwwz5FO{@*|AyZ*l?{D1rXe+Lg+hOqk( zmLWa5aJjBDa|oOPgl(Irok7JuQXd<{ljeOnY~W(mmG5k4yv3@ke|a$BMEPMhgrG7) znV6Gevbw zsj5^)d@0>kb!Sc(N>aXKMKTOeQJE@`@Q8+Ea_lp$%8ekk`RgyAW<~=<2ZzW87E&RM z<({pm98khgOtV~P9Lg|6S(XTCGGr(S88pcyv;iQ@A4jZILGw%KJICxtI$17=170K~ zLDc&+J8oP4zZvHjPt*DDyyx=&W1f7^|99|I^M9D=)eL_ZtX|lTLGUh{>w`_UyE64j z6zgN?+Kf*0>i>#96**kj;x7&>Q03P_eCLbah5A;{hLGR7U=#Y=CPYa+7R2|U$8sjA zE-Rf>Eooj>e80EBX8mU#kG?e?rAtHI^@cH+9z>>4)Mk_%iaE*_@wDIJb~BI?iQl3O zj^UOX1#*K$GZGUKa8S!nLZXr*&8hQHD&>^;v}Ae^|8Kkh=l)RZ3jhuK|4FZ3jQ_RA zf8Whx?*I81OK+X(-QNiXu$}GSt)K7m3>l6`l`D3!a+a*A%wDqY?Hp(1Mt>E(%a>qM zhTENUoRrLjchg$y8Bk0W#eDeXf`k`VxL3yT^6D!o1p<-DSp`vGBnNF|2PRe4(eGh1Y%KNqJB^%C2HadMx-fL0S-v1M@}brE<+$kYdw+=0 zw6kR-jfcp8Qq}RHXw5fUXh6SR1IlQmTaizw@k&eBd=?3}#oS?CFZ^;c%4V@O`(UKT zaZy76E>&?>hG6Or_nJ+RV6*M&Dgk?~KvymDzOFO=)%dZc2(oAm6j@YpsoR771QhE~xHCjREjPL+4-f3CA6mJCm@ArDW;PZXjj?I74pHnu>bD?O)v($_y1o`@yVI>-Gu>3%Hl@5;h!3Un7U!5QzBtWf zb)vIXtfUeXt4>?EJ-%WeFV`A&08DzDhBskEX5Hl$#u{i*Ocw8&tZr!Zr+p<^St=12ypfUjMY<|9jlq`~U9bd8AIz z0NF@01>2|~B9)>6X2Btv(_3;wBt+RXj0k`_WnmPV8Rr65LBiA0^xEIA>Cg1pbp7WF zz$@hspk7K$pQD6h4m=DI9q;2!t)XByOJjb|I{-?*zR zP+}#~L5vWPxkf%^QQ<5#ySmHfOHK~Ahjv|F~Z6LLJItE}R zm&l`Z`>Mo_UPN^v$a41;iQ{9qdl=|As+`Bwp;#5vFfRu}u1nNnsRDBgYYHVxKd9)Y z@V5*WdyoFTq?rru)1pAfg+~^xomf;P+R{SvFzMChyUxy<3gW{Rw%njiE@^~eJFb8y z`f@qopZnPY|Cb8yO7X9e|Mv!N{KvDw+5Y~2ClB!di=5f3+lxkiE)(V~{OE~**q5<8 zmQ3R6qtQ1)yc!{})E9xfQ4mhD9NRFIF+)a{KsL%P)d-*unBu4`6%C(4oW&1Hm_r@$ zp@Z(VO(Rs+H8u$)_^Dtqrf^sG&6GsHvBT+DdCR`(ym>-2#bJax?*QyN6g^Z~AW8sG z9f0cLUMeOb_&0_;w|cj{FvTNkKBzOui5eZ1~jS<{Rw;avS)jBDPme{ZG+?q%(;50uc#H zk~Eg8_-kP|+G;ZzOSPIIW&L6?`%U3%ezw5>gP7GQf7 zRo6lRtP@vifb-%SRKUfA57Ggb*ITayu5Rnss0H4_`d50ZjnDsseqsF&_V~}cc}mv* zRK$fu(+Ia({sp~d1rw0z>Xxk=y|Qf8wnGhK!(22R#;QWdTTk;I&{{ zM!8?27W?RlH=2=bq!c&6*b9W<6cogkYG#PoatM)KjDb*;JVcD5TLR%-vQGJ1)wPDvKNua#fatQnI7S_lA|2jC5sXkqg4DqY0aQ$mE~kr#XUOP+h^Ul& zEAq{m6;2`YxE?aADfg0Is57QCs+5Y%W#;bfb!iG4p%ia;gVdy2t3lrs7i^(Hb!n=0 zW?K+>0Kbu0q>#FdMeh3fkWWlL)`+IUJ4i2Ce@#ZQj$~s`%+FM+*~0!W1B6!||C;vy z(|#fT&sl%3|JltW*Q0R*Y#|86ctId+R@Ed|A?W%4I_R<3qdM^Og3_#`d02w8xt~!# zn-h^5b);`O=h_e$t9d2bwOJRhDwI3~)`H!%zQrnid875;W-H}i2X4g*ny7u%Du-2* zRceN3ZHmh9Y|{={yx*dp%k`5qjI$}~{DmF;g$@70I!=0*1kiY8230tMSC_7eZdq8} zLAP>3tA@9k)b&&3Bh2f(LRVPO73(xbVWB3CrT>u4YoP}zO(}a>rk?;Qu`XA6>#bgV z9K}b?d{DEk-Hb3+Zsi16bIkK1Eh`iw$mjaq%J8gBe=6C>N0{7Dm(|03!iqJn&N+Gp z2`AHMNg`bo(LKuOC5Z8B(c~pG{p~V}(1n_S0)h{59>cV_AJ4Qq3^PE_TFs0&AgO`v zm(w+|UPAQDO8WXn;{IW~bjJq|VmXC&i!p*-Xd2-R8a#X|!hVWj{DF*`TO?soPm!b!sCRsPDaWk2-{$^PY8%`Iz^qy#^_%Co$G;8Z1Z7td#H`>=L< zxsaesGIJ@r0q5ghPy1y&TR8tgoU8|&{{|;T|F8b(9{+bIPr3aUcz(jL3a1b0>7gvV z!rbA1f#YyWSSGY*XuJ}-937>)h4q)HsIvu?=rUGD8OVvW5%Tjtx->C zAk8+_Xt!RAh1sSl8%q^O)iCq#ojNBZxza>BYoUcP%WyoYEncO~y;FOnZ`zcGBtCwmPU;|L1w1$=Wyj^7yU zI$0}vTD1+0L7`3u+&D7T=HKbs82N3T?Z`$exy>*Mux$U{t_^^SnmG0im-XCEPf31d z-BW{DxHMf-3xazZ>(<63w@7W_9aiWql1Vp)MO*-RHBV<$E`D(#Z{Iy=8rdS#B01G@wX=Lg zZoTExCG@gN$AQ>#$Cvg!=l^D0(4}Dxnuuj2**g*jGU;<*=X+b=?-2Ec18I5_)0C4{ zNP3HQmaROLLlGu4-P#k9F4WeYY#qSfAb2drBG_i+2=*fpDIDBiCmi$WzcKVPIjj5> zuY6gvozZp5(yc6BLaS>gkHg(S)t5D-a&?(cP5iB_C2_MrMVQ=O+@Z0z%JsF0T+iY$ zpwz4~`^Gw3*CVBuW*0|hh^}F?KDD*Q?wiOXPaA+C|8g9l>q;Cn*g%cQvkokHm@x*< zHl=ibI@2atX1jpB{!e3!B8U>6QST3Rp*hZ$(SoD-{Rwj zB$&rQTPD$6w!N~f1>}^GY(A9c{Wr9APk&|y-Y`7%y1mSS5@3Nl{HTt63HE@sqHPtu zwWAA0b5;zD*^0}JcE{#V8?)x8?sGPj@Vn0i!$c%lzCoX^FrHwlrc(QpF!Ze5s~MfT zK8GZQO5*TWVeRgKVhgj;+#3!piw$1QnDMT%%fB`Wm>shFO_&&}4D}A5Q*VnrFQVO- zcj}icwrW+-wv9kh5wBU`amdHVtW&&q&VqY*%(4w>LmZrt2GkQ~bwAul4}W zB{0sF`3rZE(l>u}Y6~bajtysYXiqw7x6g=byc% zun*HS9o{zJHL}8m=+o!6pwHdLFc9&vG4(xE+C8w!0+xs+G_cQ+U z<%nZ@tbGafQo;uEh11B01vIxqp1E&I>NpAheZC1Ff{Pis-6W!p$5b-8L!) z?9d_gq#0twJKaW~T7YWx$XAOf;uhWz-dlb^DL!{^%c}_G7Db>lTb?v<_3bKS9R#JE z1YLLMR^{JJ=W1Z7^L=wQnRTax;4-m(uf5O+uOn|I$w~|y!h~ofX@;;Q$ZgZZ2|%<) zaLl5jH&c3Ee-5w!>Ao$iM6cc>zG48>rgprxKZQDfcHBQ1DB(V9Lj;s)PMLI!AH56} z*UIhhV|?d_cNdRhX#7_Bl$-o{v_g z`eBW%i@PM}2zIc@baP(K_FYPR*X?FXGJ9y_@FQL=J{*pak{>)Wj^sjki<7U1uZO{) zkHuT^58HwM^ETKoG2tI;*=fY_6<^KKxY?EvpPJr4n7!st7Sou+=c%4nP=2-OhHehd;TfYT%&K(H96}m86cvWvcQY zHXlbJpII}x?;;&+e!mUWJQTkjAW*RnJE#vXo(+ZNP|w9xft_>omXQh3)%NYOwGQjJ zTpbawe?w1gByUHG{W0F2+$?hd%d+UGT?(;Ww&Y>!BKLdSMT3s8i(YxTe(|<D82Ysr_teLdwst zQgpW|?w%Aml81eh>{IgkVF)yqpw2u$nF{(`P22)sGEFAfze0jpmDh!K)FXJbNTA@E z+WnSsgWX7*YBj5@=`My=Ucc%=km_Tu0a78`5m;AWQ4PfQCpp%>0k`Zx+F?!aC}3+` zv+)y?fQ-9*_BAosc0L#$i$mKr*!))8{^=|g)g0y#xw1ak-sv%86t%VK)9T_9f%sd> z$L#BC-zL!S?QMHgNaOkkci)*OZf<<)%)O@y*}GJLO!6rC)S4?fR{j@qC~MYUjoj^x0+ z++QyRHr@B#?`rQ(TP+bZz12I32h>uobCtRJR)9wuQV|s+LzUIv0tcX&k zl<@)OFR(MPxyAvIx}Ss(@v0!zl2Z$@@NG6i?z>~J3if8ST{kd)=sFek|4{)b}q zLlc3ompJV928Zp8F%O{H``SA$M9Qlm{}{=nxi6C;iF03&?{rI9DE&Kw2{nMPnSTjp zbzVewa(BikAth-~IcLYA@LLpygd@mjT^WlR;xfoz_FO&}OaCu+|l#kjwJSh*@YA zgy0&xkjn=M4=rAX+J?v5rIT&VAPHm2g>;N+tyT}EU-K25`!Z?ee>Nj$tj&b(jR%}p za|vrL7UH6d!n+XQ@0)W}4md z)J~8092}66rq=2lK25ZXqwZ#(sLh3EJ@g*I;txgtEj2Sd8akw~S{c_W3#%KVHvYJ`x!Shl&btGRS~VUCIRbsRCVrrHvd&f#d0AsiF;XL}Wl@l3<- zPv>b=OW}cK=0$`K?H`_q?$vq*m!~7Jtr|@RW<;=7<-VQZ14&Jf(;7_9Pmz&Qqsg7cok zZ!x!DAm0pzOevbv2x&Jf-Xbj9&M&Ky)beXmV1(#sYWq*RMT!mL8$gCK8NtP|{g|O^U<7QgMUeL9}u1aAN?ku+vA$dz)7?3kq@jf-qMUifPKFo@2tJf+J9%y z-=~HFO+{Z1fkLymK45H}@2`1a3XyLfB;fYeCd>GR)_coT>+e|gEWP&lg1;|bbtGhu zp`-WvIG-TP(ED9F-GW-kcm(kLDUu)gyM0m1mM8f(QdPd^$aT*eqrUyfS3VR4s1!@{ z#n>qjoZE^3^91g;<$?cv>nX?RzA;U)-})I#n`Em%aU5LCB)Re5vAp>$tEeQh1g3uyAkNaeM zUG+mp5>t5LT|}_L*l&e_qm$K>vE@U4q4|SKQb6y3@mIwAcl}J_{@&u(e9=!;UnpP| z?)^GCQ1-);_g39x4o~%G27Gony4eL_z2e8PM>!bQv@C^3>SwU{h z@o+baJ9VFu`Wd6dF^dWroFH|V`Z;;;ycP;`aH6=we0VM@e;RD*)@UgUp>7$5n|37( zDhK$Ob=htQo)#25Jv|kGq(H}83)J&^e@XX?XVv$7+{Dl!@F-exGs!web&$`tPf~{L zl04f+e;`~|)<5AS+U_vNur&e;VixW3BOh=99jd&*HomjW`Op+k3OdkkXrTEIklUqk zyYL=#RMj6GB=%OR6bIo$B8fSRns1L%+qAf83NbseZ;t301gMd7;9EOyP;m1+*9_NJhX@d@lbN_^OjlR50Ruq zoSw~O;*oWOu{OVgiFDEP=Bo*lt#_ehMLM&5RxLdg7r|s0oDoTR^kY_~5ee>t_H3G< zQOa_H*<1NK`swp_*yGvn(G1Gfw|?tqPG?xyR_CeABIU}Yvh(a}m2t1K0zno%ZAwDp~a?s}uISWYfh8o`&N z=k3xVSO|@tdh4(5B@b2QrY^WB*xyY+QM6323(I7jO4Xbu=i2x1z4aSJB{ZfcmOxwM z%TKo9UXSeX1OOG+*n59g9Db6{k3WuhaE${Yae+So0j{m1z|HZdoK4|e^mJtOoc;a9 zrrleYZ@xVI)HbvsI|s4;32!#X6(Nf$i`S~OFBhHt>{rUF!M9$tqoe&^+o~hS{V)E3 zu=^%+h%>!{q~4quDOfgCc*Qd=*Dt>|1W!qxw;xp_KCZ(*EPA~@KVENvXT+#}-81=R zOCoXSK$#O#Qdh7_Qy^&Xm!j$QQ2)u zN`D+OZ)-zEdW>Ivq>7RLyPv>~omSgB84Mv*R=3(&x%){A(;F#CgcXU}DFF7q#z^ugeG=FM8=n8Egt*ca1@V${%jPp$DaL_?4rH=9Y%?1BL97plVnfU)kI*a+_bRn0;!b=9`s6HlU}20CN?X;7 zr(5gqj_(KLO(M#RPPoFl)H;7JaQ-rU_vE!tr87TBR^*lmbm8UmlYhTTEaH#jw>V~o z&Bx#nijQO)Ld4JB@nPW0Ii=D6EsFrH^bHBOnz2I(y*rNg%pA!`O=dpDXg5oE%_8_4 zSq5@Eg&5c3QX1X@OvX)jD9mi`t>z;ALESeh$}{j|bOhEwd52|i;)#HRQ_+p(qT4FN zOaI1rx;n9?Z{z$55+Tm|=&X%asDJ+D6W)#>NuZBInX*3yMe@seDlVRTViVxYpkQXK zAm=Ap>Ydo2aW>rj)~-lN5c;T46oZ~EA{QpH$b_P!;H46<6~-nyLCnOQ>GXHiTFou# ztuxCAuIGxudPF(w$^a>2Y#xCrU&?fAASu}^lNL-}r?QR=Dg^0o zk5Q~VLOBpc7%3MTeG3DYj4zaZyC0uP1qX&|c;7Z{Q4E(8>q*o^WVcvs=r8uttOkqs z*%%rok#f2^$t!#)QZfftBHf@ZQ)mTy)`Aun9VPm1jAhsu#ncOYroY^P7M>L=0;fH> zb?S@T)Q^sv53mF&oHHK+xY-CBL$Xyf} zNj)D&4~I3`*=cj}MTWjpR7Fj4DmQj$e_Dh6w^$01?Oi-kR2w(Cn{b&)Xnv?H?AAbd zl_*I~_VvV*I__tJlcAr3P~CnW;~SVNgHc$8(6tlia29CLW7xBP(62f=X}QS3FSJKq zGU|AVe25i{?Mh#E4X3X2UcjmFFw;b+zzsNhXzG~~%SX^h^K|)5ZzO%Gs?IVUFdc*I z3QH#raOQvZVitozTGNL4j**@gM2n{{DCPTE65UoerW+~SF%+9;#@@#rDH%0~-YUYQ zAf+cYd8Z_b&SOcxhb_div)kbCnG}rz1WzAPw8ABaD0~rDN|Gy>_nBfXBZd%=aYGXv zht|zK6%W$!(O|0m4;;fO`8TC~f-}ODvIT5Xi-%n~bgdVWB)o=gdveizRA9?HjQWN} zh_vX#Ac}4^r~;Mkl*s&(3%exmFkk2^J*j_;Y!95TzDWMkV?i3Ji=L+IprP7jPL4xg z>MM+t=QP_Rnz5$R)*cXFIW21zQ2|XiI8;ZYy;el%G(4Ov%!d)ZM$S}UOVwoR4>l3s zccX(O?iE_m9tgVgFJ$o~MQX*-kx>wmDKZ0OXMmIntNoMm*kgEGp~qYDnaEVL6d5f4=mN9!yLHe$p{uy z2)qOUE}mz5?qLG}-a>r99=Aw^9^zGh!boSp2}5I~aTZ3IH_c1*WU(&%%#q|0KgD_| z5Vud%m>koScCDaPe{@P_p@zRC=RCW{z_NpeaeN^^g$omjq#PavqAXE?etPcSMnVeW zRLbeRUd?PZD+Lb$eTrm-MBe#jrXYi%VrG&)dW;Lx`YfWpg-QEGBtY*o{S<+GieR>+ zJcNqu8u@xzT_(XBTDF)&l-&Nlmx>{oZhHw$8FGf4-W*>U&BU4uZas7>(Y@@Zjh{Ay zX#V)E;g4;4tWri2+T5ZQ5##GQGqU@GhG7iUJN!7JNK`;OX`M4lw~a)jRd;w z>ec9#o25nbj{HY<%k9OD0n&RT({IO#R_^J0VJ02qlg6fx1E1+d>l{dOQ1OBOqI-7; zYYRdc9f7%K$K?k#TSQXe{Yj`@=E&fv2oZ zFhra*dqwt$hPn0vNf3euVww11g)UD;dqt;#?^}zAvyn;2ZF;^*a-}8#53?FXP4vpR z8n0r*p4EFy2-UhONVG*oV{Lja$L({#jq!QJ{xs}K1^HOq0|Xm=g7^&mE#@s~@l8gv zeMEw;+}X54u%AD;q;>ZUib_nynD80DNjg%b~C+J&MZ(DJdmY*FA-lq4=rV~#E;^1 z$!AcM2uW_EmoNSnJSj-V8_~#$Kl8F>evmU~soeoVQgqCv-#^Z-X+vAiYA4=o0fhx4 zksdK0qVIsk9&CRM-;>PX9q^|lvXA8iCumyY%Q3HlIlc;K78|PvRTpsRV;-S_Km9)L zmO{o?PDVyPw>Itwo@87kOEcU{b>@Klj4zH?S4PGSoln)K9IP#<`gY<7ZPVXa@cJ13 zr?Z@h%?1~(>PMo?sm583^-MKS9Ot5FsgDf*Bl6N@tMa+~UIdpi_JSB+yOtrka`|_( zekuINI0)FOqHFn5Kp8kioc|U-_fXZN%{aVL(8nHYU0>p2n{A;2i5KM>ww^NSs zW*tkrN`>O@PVO#?WEOyi3Yj;+=4a<4Sq9#yAS(qR@zumA^-hXxrv|)eI9NUGLU);+ z&|(+~`F*q+Gv@9Md8#`iYlyrL?s@!FGmOpP{83dFX2_(51%i8{4^g&bEit~6*~<$+ z`W2>nzJl_@9VLF-0`0)Q!_Dp>Bo<^>^nZ4W(!BskorrLtBX%0}9q z6#WbxpW)xFfJhKJKgM4ek4A~EjgM%XG-91mh(L5~?1}x5 z&FF!3Q?R?UxV4iAzn9fK2fBtL-4jCnJT3L2UCjd^mP{xJE5SeeM$ef`B>lkChi@_$ zD5t}Cb<4l(-CGDlxVFaB^1b@0=fgqR;Rf)-QQ1yv#SPZ>4#>|s1R#Cz^#cO)gir$2 z1V%8ii+6f~k4o2H{!L(Lpq`roU~y}Czh4W)hLHQRSdT%+MYfUQA29}0Dlzca=|Mgi zu|e9oWlGLyVUwvEjkVzo0D$LZlXBiXyHxLf3K{T!sQRZ>ooX(kFtO<%cGuE@0?7+q z_vuaC&v}s%m0Q$YW0-UnxE~TZY3`w&OL*Dbl={bL9>t0MKM|*$4k(2 zSlDk|nq96K*v6S$+YiNS2;4`DbuwrS8hHd9jR1x4b8|0Ofh_q6EuR21&Vze1NG=Lo z%ZV7Z*uru}5((+}Rv*|kjWt6z9;%5JmqSBrV**&|h0$MEzd9v9!@l+0ZC9>VYOopD ze1!P_>KpHv2?RM(QhH*5zWxh>TmM*IT(bw~dPc_6R~&L)f5mBkEy{QhUj8;n681p8CC=F_iGoM%3j!Y5OJV+y!KdETq|raWPPbnYfD)ixci{dlv%x=Pi_-k36hNqhdWx>w=7vIBfwzRD&Pg9M6RKO4PXzg&1H zfOMD9gF-%eJ(j7D%7{0_4J*W{OfDHXyyTXki$YZ>mf$?Fu(L@+OP z&!tx^)KJJbax_aygXM(`SxQ5#)Sq3F!(GCAZnwu>KS4X} zp7tj{1hy2b%l5H<1DoewNfv4ar?qE8jDYc}1TQk>9TrnW-uFL=QGx=DYsnkbb_l&? zc05wsk3Hw7*8?+W+@=~bKZ&>^SLd*!VmbN?KbY6JGPsp0sBYsnvFvu9&kpZ#omotc zKJGw;XNXINp)|^;=6Y~_3^#BA-*XIMusj3Rb(hyW#f&=u!c1*lDXKUYVMX8ek;l8`G$PS_w}oY zIbS%qq5V_r78h^(oSt7?+pe%g-g$ho{awr|D+n@mad~{&1MPMTtS%27@Ha~UtadWd z+A&XL%{noTndhzwpZmkZsJ$jVbkw`Ql^4oBZ}!%QV`8ekdOz<#Daop=rfC`5{2l$L z>K(BOR9j>7Ev=l;2}}))ik)vIu_h_MG<7!bZ49fao@d7V>=}f(c_PJ8kIl(uPllq# zIoq~OpuCJi{8UoyN31P!Vsg^}YFh!CBtvVhJxeY%* zNq@M8>3z|zF+&p3DATE@DKWux{W4u8`bh5ybo^UW1Vq2^grw>#f9w5x?VATa%qINH zR%cmA03XH*E^76S)L*%elX(7zl=;F9CfHi}`*q7#9Yt_G*F4qD$B(9~zr4`Z+%NxN zTp%%&C^z@&AB=>HL_jfUXGwmh9l+SVVWR5uK4*CKl`avPyo%en=H=-u({S#oVY)1w#C=<_0-Efl5)}e{fHi35l||t~lDehNHN*F<*b-xYcLz2dWbpY(yD79M zbp@oMd)q?SNhdW-+C1+C7`VDUX=5E?sNj8%0jYH#>LO59Y$P(J5mkvS#kr7SE6m~s zUC%N)kiZTP57_s_A1+X3K>z=MBa(#R^hl*&X9?qE>eYSR9^vao7-)bTZb!wI7x-SnvA2X36~%n`0n zrvzoUr`F3sp?%NP@5{8GAS%XEL?VHY*A5Ir;@rN+;%EUc81CKANi2t$N&2@(6rl-Q z0p6O+I>NRK>Ur@zb1PW!9*Py87RnIe%T-w5O&|Lh_wQQar53_C5vfdiv#>b0b&2rH*($Ug5s=BEi8GwRXUoxa z=_n&0_&H*2LWBNv!r9y-u}cVH`f2Tq%a|qG%Fw9!`)oP-;6UxgSQ>Ai|KOb1+|! z!t;e$99)`xn*B&95Q5NN~#K2<2~9-GLl1gAA5e1 z*xUC>ZKkJR-;$(~wYq@U%9)HV!MK89OWsbcz#m_JdHyPeL|+*Iu|Jbh1lADu`Q))q zgMo!uIuv;n)1Q3w(yH!|oY6R`R^da*h}`}+0m@WsTy+uy1@O;nxpW2}>(^o}FmnO#*fLEgRWnSYn%sfc zqJzE&{97Zk<9#kf+DW(yFw&V`A&I(^TD@Szo;nkZaiAU%4g9#P90{Tk0ZNEu59c5X zb0q&m;;DfkQ&4we-4|Ivg*cD*Ey4*KA9}7k>=O{ux8q{5PVMx={tpTtop8O2(g&fMsA!?@oqSU7hcIH_~|E z)jUX}q;&6PR`cH?=>ED%nO^3vbTwbOxZC2Ni>FkqVHH*9r_=XM_BjXqHz4TSQ#4gs z16ox$02iDzDZ$0!`$Vc4$@uT}WTsWgx;Zt8%E8}%Adpf>Ig5zhKGYgHqo)kE(?0=8-IEhnSF!E`)hJLcz2WT&x($lX@;R@}Bmidp{DohWAY< zAjA==|CbfTR=GLHSe}M}io6}l?dc9; zF zt`;8uvN7RraRGc{zI z0FkMhr;5%`a|MrCgftsoIf!_H*RPr-#9X@GhGce$)o6o`>SIs`U~tasG#|-)FN{Lx z`UwoG1_~1AK7#xJxU;ebz<4DFJh3RH4jY7m7rXAy)j#*s6(ASz4B|`ghd6)~Xhu7W z@(ft4v5UlEEJF^jY@?w>^RzkVfUbj5y+3?Fp57`CP2#&3LR>+n=$;H&|Ibn&vm3GU zrWx=q5DJp&BePns%Z2~55dhO?bb8kwy>xIv4{orn4kF%(Ek+JDtQTrEz=2S~U!YJ4 z!%VP)iRL7NWjHe!E7d`Yag_+SrlO%g85=f^YL!rfRf#(w-}jA~sX>d^{kaT_0%7&8 z9_gbVIGU*;AZ3y3OVaEqopHir=~l0a<+<0M^~;PJ#TUI+1A((>G>txdixPX0FKTJC zYpP$X9Bdl&$a02SP{sZF?pz#nT*|?oh_eY2(9VNa!~@0#po=CQBLzM*S8nf673i~I zue=_U?UTtuGsH9Tlimm+-ZD0gkkl(K8X*j*uv>JkUVoNzg#|XtxEa`55bO`>N=3<* zvF}x+njG@Q4HLZ=sc$W2{t1>g%6qCXg6162Sl7VlB}{{QI%G!Nr=K>o3A=A0bPB(n zuAT~c@og2Ss7LIF!z6IO=O*W4pz38RCajoz!GDW$8QHjg^gWA1a^ys-D?fW?2VQEw zg7F=@F?>jy;FXXciQxKA=ZhS8;S>d-z>7*l^MSCfArv79p)N1um7Td&fTk*pg#Y=f=w?9yjx$nXowOYp?@sn2P-H0JUN8eooq5 zm!bjBYkF5fVGm}LXfv3hRzH;!N!(N|#1Nj;urX#Pm)L*A{Gwu1!BaBn4F1#I7sb}4 ze#CV59gkA7pKOL!W{9Ps1Ajhe<-Aw9O(mZMl|2afw%SY5d)~qb1ab)8h3<(Z!rv zzH)&<^j8KVAB42d9AsZ$#HxL3CVFifANE9Z>Kpx?zB0NjK^s+yYyS{>%OrJb*HH1V zL_pJU`1|*$mqY+lB)W_Uv&xA+s`xD)#YFrRzak)dJz;K0{7)SbmJO&%4je|9Aq^rs zywyJNnvq4gnuC%PZ9Xl&mMoxm-5KIU(O~y0EtY-0R@X%b|DyFurs_V{hi~R`MY{U) z?5LkXKJad>fRG4`a0Wn2`{AYwTqL}h1qk{~-J6PxEz^q7!a08U%%yxIAkV|7tYu;fvGA%jMS~*Qk9C&UVH8@vL&Q zBD!K9Dh#|N^B#Dkh*(L)Z9z35g2UHES(Y`S=c%Wu>Z=pFJAT_D6^U|=RRR-4x0yj& zv-&lFLrIPyuz!mQ&vHXCufk_8wX~7=<2;KQDXQasJj&Aa!=GHT+1hsGF(VS}FwkX< zeO;5M6>kO2W3BuXT+T}5&+{b_WlqSQa3Xc5Ivd=%oHo}P5;N9+gWX>zhFSKith z)3a0tjz#evC`^yVzA+O{p>{8%IcdDK^8+?+{nWr0d!A_PH|N_G7Z2#wl~zGtdG3`_7~5>`{DT{w!lHfP1wT)(VBD+oe(p>xzFl{lhb&t?Wr#G~rCCw|wA*QT5KB zudQqXat>4!)!H{6+G+iyXw_DJ0(k|9g1og;bZOL1x!LrT(}m(Xl-OS*GC-u1mdeXk zTz1g+-eXb#ch{q$H_rjk!3UCi9q@$sR6zT&*bTf^$(LQYQs|RdR1%kD#InamCn*09 zEJfApTKq*HPuhBDl2g=XV|>;A_#jg8s#uJ~rPM&|G>ccuSfvtMc^O z+v#KZ{!9v9D2unnQlL!?k*oUTl~Wm(H$(|l&RrJ6^(S&-!fg7vE)7w8li*uPy(OMVW2sc{ zHy>}QU@Xe@;1%~oVI6RXH?BVCcM-wO&(!#-wXw1F)G#4C8Cu31ATMkZOL+mGldW0i z)MFs>B550KzjMNYqJIRGPa*hz@1Na;W$bc(g{=5NCc>BQMw7usu|ldV#{IpW=w|jq zC>N-x?A7wJItKI$(FB?NkpB98_Qt@z0HtRxumdG2MKj>tZ~`8rq$m^B>(Z5iQ49Y? zPSFGZN+;K<{fnI9OPz21hn#}Q)aFYM4ie%VR@Y}B5RuO1{jN4ZbQXz9>|R&*t+4TD zgFIcos(3~Afblx7CdS7|yr<0}^IQ4-5&S$>1o~MQ zgfp*zIl|nFYoOQN!JQ~rd%2WY1zc~8zfzD#2|&c}0|6fPD>|K`GGw3*Ddx--c6~>( zoNPc$cPUwxJ72GA4V-tps4-cQcw7`1wXFL zU^=lepds_4{DxZ;^%y8Vb(Sjn^`Uq4>SK0&{niB7nNlGE%z=&nS_HNd#mL>~C`gm{sXTt2$bFbjP=&4XUng5-hQt0@9q^Dws znE#ueij;%8Y<{CQaL#Ae9b=r1y5R;Iyj&gMfqr>OIYWG+ZhutU9pI=9$b<9z{$dFL zwx!74KwqzCTG8icCYep&yx`|eQ|uYyhH1>^s7p-;9wgV=bC+QwkZM5+rF{`{kCxGa zFs&*EsoXGgySWyYX^DQD#L;wOZRC`di{c4k2KrJ9!Z!wN%q4$V)nmRt3=vMt@n}R7 zez|~__=bRBuE@L(ae%uimO4r|Zoe8Ptigze9cBwH+1f5VMao z&u0)tr#}bwZF*Acj{q1B&OhvwL=$|yv8^Y`0E~#ooW-&e9o&Gc51&lQnW3=*-bcuM z5uAJ3-x!M}cKU@~VXUHIODcZiDX($4o$>iYcXV6ISe7y7=1gbl9{#2Q`s^eo(*J9E zisQY>pz$+1)|_~JBtNs@ht~bg2dUULF8H5AQU zJH;qor?S{2xztl?}EKb*2EsWCJFFI^L+uPql9`Q+=pLe=e7 z%E_ra5xPF<XomREbPHD5_roLF%&+~uuVtax|)|D4^kowSZ)ZZYuMF64W2kFhS=JJ2o61x$j_xw)?)kF^nq0-AF z&J&nL>w??QVqJVaA#;um6@N8L!!?XZTM+*Y3;c3x)z#ER2c1d>YUuQ7-;l9dJh*GT zKl+MAE!#0PoNQHRJjqrVJ&)N&9nMot=XQEDsW5S#NJ^@!F4ytm6^%`lx=}K&e?v$K z)1CUMzM^Bc_N**L>!d=BrgiMNJ#M~;z>PC?Mv=3SzSOafFr}WnrXDyRJQAyjZcvgx zCzk!yK5(Yhp@D6K%gW-%UL}F`XSe2YD3xxuoDDM@PLUo|IP*SW0)v3PZd0U9p4xrhCRFlA;7tC6;CIIH4?OOySZW<;R>J>;v<%<_nFR#{jeudz(h zmM@CYDs5dV-l}EUyjtv437hrAk+=lLPsK#ju`_V4*RUGLWOrAo0T4d8%>5+^CV)KS z4R0JJ?J~R-rk?eSB#b-UerzdwywsQ772_TbLmPx#1-8kY6bCd05uWV(G{Yn8Dmv~V z#;(1tJ*z%SrBdGaJQWnGtonodT$srS8D(+zAtEYPk*slW#&G~FfP zXyPF+Uqqx@iA^VeE0fDCRr8hKoB(N!2O6{&Y{Tl;F|zHW@eOlhQNY+m8skIi7A`%7 z5ldRGjU!yxQlB&O2k2*RYd7GMr;@9Ra0SG=#j@F#8E*_qG3+DE0#vo@3QqLa*lD|v zme-!9m&`ew?K(f#_d~DdUoJw2QV=e(MejeGp+8lfJN?x<5eZTqz_Txa3A3B`z}GJT zU{g-TZ<19wl)q^I-%wJZ|7FuE9nvqrZ9=R|(fH^87ceQG|36_;@RIThG*o1_p@B89 zwP0B=$IR(r+re27hBTnSmc{Q+-P?HiNoJSavLg8nBy-z?jw~b0yp`Cze0jYrI%rxS z&csV*9P&1xcdmECV1P$E$8;%%1*L$;lxy8>0hgb-x)`-i4oSM`w{X3`%s$pFi^+>}Po{02n9Sv(7WCD5R3!wDt2}ILxdfR0;$< z*Ak`bYtBl+%7NU8a_lB{KB0AJU4ec8K0Udtge1od#d2oI=-L>ZuaqTJ($%!#X`O7L zjWAZ-cGUJ&Y$`ta7=?*HojYQSvHw0}$ZB|HP`TQDCSscW(ve9jB#3;p2o?aOnGOFu z@P!;99nl!dw@6Q@wR9<_{8Bm8{#vxu;A2*NuR0crev1qKjxtRwGnW;dpjApuyYV!X6{d7OdP_hlSWpp#>90>7vrsh z$e(ym556gEhKLwk!!aCg&+)PxlvbMvKj2_1r#V(wAV?zprPQRIgrJq7v05}tZU-2Z zFLJyo=h7Zzp`hg;{TS(!9&x-PzDSRr0A3cdS>yMMzv)vUWYFLe>K*_!dCD= zjzwJwW4*8r19I5dI7<&Iva&=fm^tGx(=n|V^1?0iYJUZ5=- z^PXry{?%=P*IjB2FcfAu^73n@7`Y}jEgg<&nRT7YE19+0b|3;{<&h4+=lu)gIgloH zEEY;zV29?d;Ql_S6Zj0e;&%F!ZfQCME?=_n5!2@#U*?LvM7_sSB}isA97@m$^-I77 zON>bUrMXQ}7ZL0u|AD=wk#E!X%kfj^=d4Hyq2)Qmda13V5r@T&y?0Yi=>yDCx0+E2 z_x3?eTNO9Ayg?Rn=US!jiX0|X_8H{t;!}{{(}NHxz6k5TXs z{NFQDAmFs`-;5N-)%F;0R%I46TmmmZ;#W_~s2Ok3ogVfax2xJPaxWWP$eUK=^N4C~ z?HX$8qtXnjdSHLx&eT1o=m*3Dv`z%>FubX{FS1vy-g>$u`ho^A?r#G(q}CjB5)oWJ zdbq}N2@sMj^iq zZGC~?$cUKOX=;}^6_VxL=?^1xZLTz3sr&ev2WT?3nEbe;m>7)4B|LwN6;_vpZfnF| zFNbsq5sF;P+y00WxzX#XWOzD9sH#^q#VCt4Q?rUS{!CUbtjSWX##1r+byP**&Od7Z z*2^uL_z0)lro?!nQ}&yAuGZYHrGk)jO<~$TtZz?H$H_`ETeGq26eeJrK#d#r>D4x- z_GC;{fLXOHaKx(Pb(b$ukRaY7yFY(~YiDFow^QBzzL+(qn~>$LL)+AL@rZGg>h~ay zKYqZ*ar41>RO^<2X@NZ&BY)*UDr0T8JDD;}F#@xu9A1Hl+vOn63=ltmSul`07jy_3 zzbEWBbpxN{^E(xQ*L>Yrly7L)&c<@>*Iu9POZOXN-O|0z#%DHHk6)XcYG=JftXX0{ zFob&IPyhj+Tha^ZzXdK9Ob$!D{d8wL7&co!I zFBP$-Ob2?c03=rpuwT9o)QTy%JqZ-_sX7Gk|3pptv_h}54SR9+XH5ehKG!M$eew$0 zUz~ZGYu^iwUnx+*tTRM=F~#6rdS@ubrl+a}AeWT7vZ-tFYTZ%1E#`|a5ve)1|0W<4JOeG=wGzY#1@OR@s| z`-MOl6bPlge`h0mk)u*Q?G*xsE8B|2e_nK10WS(Z?tMgo05C8xAn>h6U>7V97wmrk DeRrLw literal 0 HcmV?d00001 diff --git a/charts/newrelic/nri-bundle/4.3.200/.helmignore b/charts/newrelic/nri-bundle/4.3.200/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/.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/newrelic/nri-bundle/4.3.200/Chart.lock b/charts/newrelic/nri-bundle/4.3.200/Chart.lock new file mode 100644 index 000000000..c885dcf31 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/Chart.lock @@ -0,0 +1,33 @@ +dependencies: +- name: newrelic-infrastructure + repository: https://newrelic.github.io/nri-kubernetes + version: 3.3.3 +- name: nri-prometheus + repository: https://newrelic.github.io/nri-prometheus + version: 2.1.1 +- name: nri-metadata-injection + repository: https://newrelic.github.io/k8s-metadata-injection + version: 3.0.1 +- name: newrelic-k8s-metrics-adapter + repository: https://newrelic.github.io/newrelic-k8s-metrics-adapter + version: 0.7.4 +- name: kube-state-metrics + repository: https://kubernetes.github.io/kube-state-metrics + version: 2.13.2 +- name: nri-kube-events + repository: https://newrelic.github.io/nri-kube-events + version: 2.2.2 +- name: newrelic-logging + repository: https://newrelic.github.io/helm-charts + version: 1.10.9 +- name: newrelic-pixie + repository: https://newrelic.github.io/helm-charts + version: 1.5.1 +- name: pixie-operator-chart + repository: https://pixie-operator-charts.storage.googleapis.com + version: 0.0.26 +- name: newrelic-infra-operator + repository: https://newrelic.github.io/newrelic-infra-operator + version: 0.6.0 +digest: sha256:991e5176a2233cedb6eb1fbf49cd38ce52d2123a2fadf5a352e96cc42a672e8e +generated: "2022-05-04T13:51:43.981149+02:00" diff --git a/charts/newrelic/nri-bundle/4.3.200/Chart.yaml b/charts/newrelic/nri-bundle/4.3.200/Chart.yaml new file mode 100644 index 000000000..7f4f13840 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/Chart.yaml @@ -0,0 +1,77 @@ +annotations: + catalog.cattle.io/certified: partner + catalog.cattle.io/display-name: New Relic + catalog.cattle.io/release-name: newrelic-bundle +apiVersion: v2 +dependencies: +- condition: ksm.enabled + name: kube-state-metrics + repository: file://./charts/kube-state-metrics +- condition: newrelic-infra-operator.enabled + name: newrelic-infra-operator + repository: file://./charts/newrelic-infra-operator +- condition: infrastructure.enabled + name: newrelic-infrastructure + repository: file://./charts/newrelic-infrastructure +- condition: metrics-adapter.enabled + name: newrelic-k8s-metrics-adapter + repository: file://./charts/newrelic-k8s-metrics-adapter +- condition: logging.enabled + name: newrelic-logging + repository: file://./charts/newrelic-logging +- condition: newrelic-pixie.enabled + name: newrelic-pixie + repository: file://./charts/newrelic-pixie +- condition: kubeEvents.enabled + name: nri-kube-events + repository: file://./charts/nri-kube-events +- condition: webhook.enabled + name: nri-metadata-injection + repository: file://./charts/nri-metadata-injection +- condition: prometheus.enabled + name: nri-prometheus + repository: file://./charts/nri-prometheus +- alias: pixie-chart + condition: pixie-chart.enabled + name: pixie-operator-chart + repository: file://./charts/pixie-operator-chart + version: 0.0.26 +description: A chart groups together the individual charts for the New Relic Kubernetes + solution for more comfortable deployment. +home: https://github.com/newrelic/helm-charts +icon: https://newrelic.com/themes/custom/curio/assets/mediakit/new_relic_logo_vertical.png +keywords: +- infrastructure +- newrelic +- monitoring +kubeVersion: 1.16-0 - 1.22-0 +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: 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/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 +version: 4.3.200 diff --git a/charts/newrelic/nri-bundle/4.3.200/README.md b/charts/newrelic/nri-bundle/4.3.200/README.md new file mode 100644 index 000000000..d4637b030 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/README.md @@ -0,0 +1,138 @@ +# nri-bundle + +![Version: 4.3.2](https://img.shields.io/badge/Version-4.3.2-informational?style=flat-square) + +A chart groups together the individual charts for the New Relic Kubernetes solution for more comfortable deployment. + +**Homepage:** + +## 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/master/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/master/charts/newrelic-infrastructure) +chart, as defined in their [`values.yml` file](https://github.com/newrelic/nri-kubernetes/blob/master/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: + 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 +``` + +## 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. + +## 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.customSecretInsightsKey | string | `""` | Key in the Secret object where the insights key is stored | +| 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 | +| infrastructure.enabled | bool | `true` | Install the [`newrelic-infrastructure` chart](https://github.com/newrelic/nri-kubernetes/tree/main/charts/newrelic-infrastructure) | +| ksm.enabled | bool | `false` | Install the [`kube-state-metrics` chart from the stable helm charts repository](https://github.com/kubernetes/kube-state-metrics/tree/master/charts/kube-state-metrics) 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 | +| kubeEvents.enabled | bool | `false` | Install the [`nri-kube-events` chart](https://github.com/newrelic/nri-kube-events/tree/main/charts/nri-kube-events) | +| logging.enabled | bool | `false` | Install the [`newrelic-logging` chart](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging) | +| 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-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-pixie.enabled | bool | `false` | Install the [`newrelic-pixie`](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-pixie) | +| pixie-chart.enabled | bool | `false` | Install the [`pixie-chart` chart](https://docs.pixielabs.ai/installing-pixie/install-schemes/helm/#3.-deploy) | +| prometheus.enabled | bool | `false` | Install the [`nri-prometheus` chart](https://github.com/newrelic/nri-prometheus/tree/main/charts/nri-prometheus) | +| webhook.enabled | bool | `true` | Install the [`nri-metadata-injection` chart](https://github.com/newrelic/k8s-metadata-injection/tree/main/charts/nri-metadata-injection) | + +## 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/newrelic/nri-bundle/4.3.200/README.md.gotmpl b/charts/newrelic/nri-bundle/4.3.200/README.md.gotmpl new file mode 100644 index 000000000..16a18ecb9 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/README.md.gotmpl @@ -0,0 +1,100 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +## 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/master/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/master/charts/newrelic-infrastructure) +chart, as defined in their [`values.yml` file](https://github.com/newrelic/nri-kubernetes/blob/master/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: + 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 +``` + +## 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. + +{{ template "chart.valuesSection" . }} + +{{ if .Maintainers }} +## Maintainers +{{ range .Maintainers }} +{{- if .Name }} +{{- if .Url }} +* [{{ .Name }}]({{ .Url }}) +{{- else }} +* {{ .Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/app-readme.md b/charts/newrelic/nri-bundle/4.3.200/app-readme.md new file mode 100644 index 000000000..61e550787 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/.helmignore b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/.helmignore new file mode 100644 index 000000000..f0c131944 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/Chart.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/Chart.yaml new file mode 100644 index 000000000..b7f6ddf90 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +appVersion: 1.9.8 +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 +name: kube-state-metrics +sources: +- https://github.com/kubernetes/kube-state-metrics/ +version: 2.13.2 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/LICENSE b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/LICENSE new file mode 100644 index 000000000..393b7a33b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/LICENSE @@ -0,0 +1,202 @@ + + 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 The Helm Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/OWNERS b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/OWNERS new file mode 100644 index 000000000..206b4fee7 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/OWNERS @@ -0,0 +1,6 @@ +approvers: +- tariq1890 +- mrueg +reviewers: +- tariq1890 +- mrueg diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/README.md b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/README.md new file mode 100644 index 000000000..e93a3d252 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/README.md @@ -0,0 +1,66 @@ +# kube-state-metrics Helm Chart + +Installs the [kube-state-metrics agent](https://github.com/kubernetes/kube-state-metrics). + +## Get Repo Info + +```console +helm repo add kube-state-metrics https://kubernetes.github.io/kube-state-metrics +helm repo update +``` + +_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Chart + +```console +# Helm 3 +$ helm install [RELEASE_NAME] kube-state-metrics/kube-state-metrics [flags] + +# Helm 2 +$ helm install --name [RELEASE_NAME] kube-state-metrics/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 3 +$ helm uninstall [RELEASE_NAME] + +# Helm 2 +# helm delete --purge [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 3 or 2 +$ helm upgrade [RELEASE_NAME] kube-state-metrics/kube-state-metrics [flags] +``` + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### From stable/kube-state-metrics + +You can upgrade in-place: + +1. [get repo info](#get-repo-info) +1. [upgrade](#upgrading-chart) your existing release name using the new chart repo + +## 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 kube-state-metrics/kube-state-metrics +``` + +You may also `helm show values` on this chart's [dependencies](#dependencies) for additional options. diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/NOTES.txt b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/NOTES.txt new file mode 100644 index 000000000..5a646e0cc --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/NOTES.txt @@ -0,0 +1,10 @@ +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. + diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/_helpers.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/_helpers.tpl new file mode 100644 index 000000000..6ae0e647f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/_helpers.tpl @@ -0,0 +1,47 @@ +{{/* 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 -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..af158c512 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/clusterrolebinding.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.rbac.create .Values.rbac.useClusterRole -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + 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.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/deployment.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/deployment.yaml new file mode 100644 index 000000000..5f6b64457 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/deployment.yaml @@ -0,0 +1,216 @@ +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: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app.kubernetes.io/instance: "{{ .Release.Name }}" + app.kubernetes.io/managed-by: "{{ .Release.Service }}" + app.kubernetes.io/version: "{{ .Chart.AppVersion }}" +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + replicas: {{ .Values.replicas }} +{{- if .Values.autosharding.enabled }} + serviceName: {{ template "kube-state-metrics.fullname" . }} + volumeClaimTemplates: [] +{{- end }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + app.kubernetes.io/instance: "{{ .Release.Name }}" +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 8 }} +{{- end }} +{{- 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: + fsGroup: {{ .Values.securityContext.fsGroup }} + runAsGroup: {{ .Values.securityContext.runAsGroup }} + runAsUser: {{ .Values.securityContext.runAsUser }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + containers: + - name: {{ .Chart.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 }} + {{- range .Values.extraArgs }} + - {{ . }} + {{- end }} +{{ end }} +{{ if .Values.collectors.certificatesigningrequests }} + - --collectors=certificatesigningrequests +{{ end }} +{{ if .Values.collectors.configmaps }} + - --collectors=configmaps +{{ end }} +{{ if .Values.collectors.cronjobs }} + - --collectors=cronjobs +{{ end }} +{{ if .Values.collectors.daemonsets }} + - --collectors=daemonsets +{{ end }} +{{ if .Values.collectors.deployments }} + - --collectors=deployments +{{ end }} +{{ if .Values.collectors.endpoints }} + - --collectors=endpoints +{{ end }} +{{ if .Values.collectors.horizontalpodautoscalers }} + - --collectors=horizontalpodautoscalers +{{ end }} +{{ if .Values.collectors.ingresses }} + - --collectors=ingresses +{{ end }} +{{ if .Values.collectors.jobs }} + - --collectors=jobs +{{ end }} +{{ if .Values.collectors.limitranges }} + - --collectors=limitranges +{{ end }} +{{ if .Values.collectors.mutatingwebhookconfigurations }} + - --collectors=mutatingwebhookconfigurations +{{ end }} +{{ if .Values.collectors.namespaces }} + - --collectors=namespaces +{{ end }} +{{ if .Values.collectors.networkpolicies }} + - --collectors=networkpolicies +{{ end }} +{{ if .Values.collectors.nodes }} + - --collectors=nodes +{{ end }} +{{ if .Values.collectors.persistentvolumeclaims }} + - --collectors=persistentvolumeclaims +{{ end }} +{{ if .Values.collectors.persistentvolumes }} + - --collectors=persistentvolumes +{{ end }} +{{ if .Values.collectors.poddisruptionbudgets }} + - --collectors=poddisruptionbudgets +{{ end }} +{{ if .Values.collectors.pods }} + - --collectors=pods +{{ end }} +{{ if .Values.collectors.replicasets }} + - --collectors=replicasets +{{ end }} +{{ if .Values.collectors.replicationcontrollers }} + - --collectors=replicationcontrollers +{{ end }} +{{ if .Values.collectors.resourcequotas }} + - --collectors=resourcequotas +{{ end }} +{{ if .Values.collectors.secrets }} + - --collectors=secrets +{{ end }} +{{ if .Values.collectors.services }} + - --collectors=services +{{ end }} +{{ if .Values.collectors.statefulsets }} + - --collectors=statefulsets +{{ end }} +{{ if .Values.collectors.storageclasses }} + - --collectors=storageclasses +{{ end }} +{{ if .Values.collectors.validatingwebhookconfigurations }} + - --collectors=validatingwebhookconfigurations +{{ end }} +{{ if .Values.collectors.verticalpodautoscalers }} + - --collectors=verticalpodautoscalers +{{ end }} +{{ if .Values.collectors.volumeattachments }} + - --collectors=volumeattachments +{{ end }} +{{ if .Values.namespace }} + - --namespace={{ .Values.namespace | 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.selfMonitor.telemetryHost }} + - --telemetry-host={{ .Values.selfMonitor.telemetryHost }} +{{ end }} + - --telemetry-port=8081 +{{- if .Values.kubeconfig.enabled }} + volumeMounts: + - name: kubeconfig + mountPath: /opt/k8s/.kube/ + readOnly: true +{{- end }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + ports: + - containerPort: 8080 + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 5 + timeoutSeconds: 5 + readinessProbe: + httpGet: + path: / + port: 8080 + initialDelaySeconds: 5 + timeoutSeconds: 5 +{{- if .Values.resources }} + resources: +{{ toYaml .Values.resources | indent 10 }} +{{- end }} +{{- if .Values.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .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.kubeconfig.enabled}} + volumes: + - name: kubeconfig + secret: + secretName: {{ template "kube-state-metrics.fullname" . }}-kubeconfig +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/kubeconfig-secret.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/kubeconfig-secret.yaml new file mode 100644 index 000000000..a7800d7ad --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/kubeconfig-secret.yaml @@ -0,0 +1,15 @@ +{{- if .Values.kubeconfig.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kube-state-metrics.fullname" . }}-kubeconfig + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app.kubernetes.io/instance: "{{ .Release.Name }}" + app.kubernetes.io/managed-by: "{{ .Release.Service }}" +type: Opaque +data: + config: '{{ .Values.kubeconfig.secret }}' +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/pdb.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/pdb.yaml new file mode 100644 index 000000000..d3ef8104e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/pdb.yaml @@ -0,0 +1,20 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: policy/v1beta1 +kind: PodDisruptionBudget +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app.kubernetes.io/instance: "{{ .Release.Name }}" + app.kubernetes.io/managed-by: "{{ .Release.Service }}" +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/podsecuritypolicy.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..e822ba0e7 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/podsecuritypolicy.yaml @@ -0,0 +1,42 @@ +{{- if .Values.podSecurityPolicy.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} +{{- 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/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/psp-clusterrole.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/psp-clusterrole.yaml new file mode 100644 index 000000000..217abc950 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/psp-clusterrole.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.podSecurityPolicy.enabled .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + 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/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml new file mode 100644 index 000000000..feb97f228 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.podSecurityPolicy.enabled .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + 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.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/role.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/role.yaml new file mode 100644 index 000000000..c493f1675 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/role.yaml @@ -0,0 +1,192 @@ +{{- if and (eq $.Values.rbac.create true) (not .Values.rbac.useExistingRole) -}} +{{- if eq .Values.rbac.useClusterRole false }} +{{- range (split "," $.Values.namespace) }} +{{- end }} +{{- end -}} +--- +apiVersion: rbac.authorization.k8s.io/v1 +{{- if eq .Values.rbac.useClusterRole false }} +kind: Role +{{- else }} +kind: ClusterRole +{{- end }} +metadata: + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" $ }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + name: {{ template "kube-state-metrics.fullname" $ }} +{{- if eq .Values.rbac.useClusterRole false }} + namespace: {{ . }} +{{- end }} +rules: +{{ if $.Values.collectors.certificatesigningrequests }} +- apiGroups: ["certificates.k8s.io"] + resources: + - certificatesigningrequests + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.configmaps }} +- apiGroups: [""] + resources: + - configmaps + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.cronjobs }} +- apiGroups: ["batch"] + resources: + - cronjobs + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.daemonsets }} +- apiGroups: ["extensions", "apps"] + resources: + - daemonsets + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.deployments }} +- apiGroups: ["extensions", "apps"] + resources: + - deployments + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.endpoints }} +- apiGroups: [""] + resources: + - endpoints + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.horizontalpodautoscalers }} +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.ingresses }} +- apiGroups: ["extensions", "networking.k8s.io"] + resources: + - ingresses + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.jobs }} +- apiGroups: ["batch"] + resources: + - jobs + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.limitranges }} +- apiGroups: [""] + resources: + - limitranges + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.mutatingwebhookconfigurations }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: + - mutatingwebhookconfigurations + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.namespaces }} +- apiGroups: [""] + resources: + - namespaces + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.networkpolicies }} +- apiGroups: ["networking.k8s.io"] + resources: + - networkpolicies + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.nodes }} +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.persistentvolumeclaims }} +- apiGroups: [""] + resources: + - persistentvolumeclaims + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.persistentvolumes }} +- apiGroups: [""] + resources: + - persistentvolumes + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.poddisruptionbudgets }} +- apiGroups: ["policy"] + resources: + - poddisruptionbudgets + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.pods }} +- apiGroups: [""] + resources: + - pods + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.replicasets }} +- apiGroups: ["extensions", "apps"] + resources: + - replicasets + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.replicationcontrollers }} +- apiGroups: [""] + resources: + - replicationcontrollers + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.resourcequotas }} +- apiGroups: [""] + resources: + - resourcequotas + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.secrets }} +- apiGroups: [""] + resources: + - secrets + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.services }} +- apiGroups: [""] + resources: + - services + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.statefulsets }} +- apiGroups: ["apps"] + resources: + - statefulsets + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.storageclasses }} +- apiGroups: ["storage.k8s.io"] + resources: + - storageclasses + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.validatingwebhookconfigurations }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: + - validatingwebhookconfigurations + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.volumeattachments }} +- apiGroups: ["storage.k8s.io"] + resources: + - volumeattachments + verbs: ["list", "watch"] +{{ end -}} +{{ if $.Values.collectors.verticalpodautoscalers }} +- apiGroups: ["autoscaling.k8s.io"] + resources: + - verticalpodautoscalers + verbs: ["list", "watch"] +{{ end -}} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/rolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/rolebinding.yaml new file mode 100644 index 000000000..732174a33 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/rolebinding.yaml @@ -0,0 +1,27 @@ +{{- if and (eq .Values.rbac.create true) (eq .Values.rbac.useClusterRole false) -}} +{{- range (split "," $.Values.namespace) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" $ }} + helm.sh/chart: {{ $.Chart.Name }}-{{ $.Chart.Version }} + app.kubernetes.io/managed-by: {{ $.Release.Service }} + app.kubernetes.io/instance: {{ $.Release.Name }} + 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.fullname" $ }} + namespace: {{ template "kube-state-metrics.namespace" $ }} +{{- end -}} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/service.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/service.yaml new file mode 100644 index 000000000..4f8e4a497 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/service.yaml @@ -0,0 +1,42 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app.kubernetes.io/instance: "{{ .Release.Name }}" + app.kubernetes.io/managed-by: "{{ .Release.Service }}" +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} + 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 }} + {{- if .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + targetPort: 8080 + {{ if .Values.selfMonitor.enabled }} + - name: "metrics" + protocol: TCP + port: {{ .Values.selfMonitor.telemetryPort | default 8081 }} + targetPort: 8081 + {{ end }} +{{- if .Values.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.service.loadBalancerIP }}" +{{- end }} + selector: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/serviceaccount.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/serviceaccount.yaml new file mode 100644 index 000000000..2e8a1ee38 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- if .Values.serviceAccount.annotations }} + annotations: +{{ toYaml .Values.serviceAccount.annotations | indent 4 }} +{{- end }} +imagePullSecrets: +{{ toYaml .Values.serviceAccount.imagePullSecrets | indent 2 }} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/servicemonitor.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/servicemonitor.yaml new file mode 100644 index 000000000..7d1cd7aa1 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/servicemonitor.yaml @@ -0,0 +1,34 @@ +{{- 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: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app.kubernetes.io/instance: "{{ .Release.Name }}" + app.kubernetes.io/managed-by: "{{ .Release.Service }}" + {{- if .Values.prometheus.monitor.additionalLabels }} +{{ toYaml .Values.prometheus.monitor.additionalLabels | indent 4 }} + {{- end }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels | indent 4 }} +{{- end }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + endpoints: + - port: http + {{- if .Values.prometheus.monitor.honorLabels }} + honorLabels: true + {{- end }} + {{ if .Values.selfMonitor.enabled }} + - port: metrics + {{- if .Values.prometheus.monitor.honorLabels }} + honorLabels: true + {{- end }} + {{ end }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/stsdiscovery-role.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/stsdiscovery-role.yaml new file mode 100644 index 000000000..9770b0498 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/stsdiscovery-role.yaml @@ -0,0 +1,29 @@ +{{- 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: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} +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/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml new file mode 100644 index 000000000..6a2e5bfe7 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml @@ -0,0 +1,20 @@ +{{- 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: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/values.yaml new file mode 100644 index 000000000..9522cfe0c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/kube-state-metrics/values.yaml @@ -0,0 +1,179 @@ +# Default values for kube-state-metrics. +prometheusScrape: true +image: + repository: k8s.gcr.io/kube-state-metrics/kube-state-metrics + tag: v1.9.8 + pullPolicy: IfNotPresent + +imagePullSecrets: [] +# - name: "image-pull-secret" + +# 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 + +# 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: "" + annotations: {} + +customLabels: {} + +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 + +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 + additionalLabels: {} + namespace: "" + honorLabels: false + +## 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: [] + +securityContext: + enabled: true + runAsGroup: 65534 + runAsUser: 65534 + fsGroup: 65534 + +## 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: [] + +# 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: {} + +# Available collectors for kube-state-metrics. By default all available +# collectors are enabled. +collectors: + certificatesigningrequests: true + configmaps: true + cronjobs: true + daemonsets: true + deployments: true + endpoints: true + horizontalpodautoscalers: true + ingresses: true + jobs: true + limitranges: true + mutatingwebhookconfigurations: true + namespaces: true + networkpolicies: true + nodes: true + persistentvolumeclaims: true + persistentvolumes: true + poddisruptionbudgets: true + pods: true + replicasets: true + replicationcontrollers: true + resourcequotas: true + secrets: true + services: true + statefulsets: true + storageclasses: true + validatingwebhookconfigurations: true + verticalpodautoscalers: false + volumeattachments: true + +# Enabling kubeconfig will pass the --kubeconfig argument to the container +kubeconfig: + enabled: false + # base64 encoded kube-config file + secret: + +# Namespace to be enabled for collecting resources. By default all namespaces are collected. +# namespace: "" + +## 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 overriden +selfMonitor: + enabled: false + # telemetryHost: 0.0.0.0 + # telemetryPort: 8081 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/.helmignore b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/.helmignore new file mode 100644 index 000000000..f62b5519e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/.helmignore @@ -0,0 +1 @@ +templates/admission-webhooks/job-patch/README.md diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/Chart.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/Chart.yaml new file mode 100644 index 000000000..0d75d1e9b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +appVersion: 0.6.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/assets/newrelic/source/NewRelic-logo-square.svg +keywords: +- infrastructure +- newrelic +- monitoring +maintainers: +- name: douglascamata +- name: paologallinaharbur +- name: davidbrota +- name: gsanchezgavier +- name: roobre +name: newrelic-infra-operator +sources: +- https://github.com/newrelic/newrelic-infra-operator +version: 0.6.0 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/README.md b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/README.md new file mode 100644 index 000000000..c12e4ed3b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/README.md @@ -0,0 +1,142 @@ +# newrelic-infra-operator + +## Chart Details + +This chart will deploy the [New Relic Infrastructure Operator][1], which injects the New Relic Infrastructure solution +as a sidecar to specific pods. +This is typically used in environments where DaemonSets are not available, such as EKS Fargate. + +## Configuration + + +| 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 preferred configuration option if both `licenseKey` and `customSecret` are specified. | | +| `global.fargate` - `fargate` | Must be set to `true` when deploying in an EKS Fargate environment. Adds the default policies and customAttributes to inject on fargate | | +| `image.repository` | The container to pull. | `newrelic/newrelic-infra-operator` | +| `image.pullPolicy` | The pull policy. | `IfNotPresent` | +| `image.tag` | The version of the image to pull. | `appVersion` | +| `image.pullSecrets` | The image pull secrets. | `nil` | +| `admissionWebhooksPatchJob.image.repository` | The job container to pull. | `k8s.gcr.io/ingress-nginx/kube-webhook-certgen` | +| `admissionWebhooksPatchJob.image.pullPolicy` | The job pull policy. | `IfNotPresent` | +| `admissionWebhooksPatchJob.image.pullSecrets` | Image pull secrets. | `nil` | +| `admissionWebhooksPatchJob.image.tag` | The job version of the container to pull. | `v1.1.1` | +| `admissionWebhooksPatchJob.volumeMounts` | Additional Volume mounts for Cert Job. | `[]` | +| `admissionWebhooksPatchJob.volumes` | Additional Volumes for Cert Job. | `[]` | +| `replicas` | Number of replicas in the deployment. | `1` | +| `resources` | Resources you wish to assign to the pod. | See Resources below | +| `serviceAccount.create` | If true a service account would be created and assigned for the webhook and the job. | `true` | +| `serviceAccount.name` | The service account to assign to the webhook and the job. If `serviceAccount.create` is true then this name will be used when creating the service account; if this value is not set or it evaluates to false, then when creating the account the returned value from the template `newrelic-infra-operator.fullname` will be used as name. | | +| `certManager.enabled` | Use cert-manager to provision the MutatingWebhookConfiguration certs. | `false` | +| `podSecurityContext.enabled` | Enable custom Pod Security Context. | `false` | +| `podSecurityContext.fsGroup` | fsGroup for Pod Security Context. | `1001` | +| `podSecurityContext.runAsUser` | runAsUser UID for Pod Security Context. | `1001` | +| `podSecurityContext.runAsGroup` | runAsGroup GID for Pod Security Context. | `1001` | +| `podAnnotations` | If you wish to provide additional annotations to apply to the pod(s), specify them here. | | +| `priorityClassName` | Scheduling priority of the pod. | `nil` | +| `nodeSelector` | Node label to use for scheduling. | `{}` | +| `timeoutSeconds` | Seconds to wait for a webhook to respond. The timeout value must be between 1 and 30 seconds. | `30` | +| `tolerations` | List of node taints to tolerate (requires Kubernetes >= 1.6) | `[]` | +| `affinity` | Node affinity to use for scheduling. | `{}` | +| `config.ignoreMutationErrors` | If true it instruments the operator to ignore injection error instead of failing. | `true` | +| `config.infraAgentInjection.policies[]` | 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. | `[podSelector{matchExpressions[{key:"label.eks.amazonaws.com/fargate-profile",operator:"Exists"}]}]` | +| `config.infraAgentInjection.policies[].podSelector` | Selector on Pod Labels. | | +| `config.infraAgentInjection.policies[].namespaceSelector` | Selector on Namespace labels. | | +| `config.infraAgentInjection.policies[].namespaceName` | If set only pods belonging to such namespace matches the policy. | | +| `config.infraAgentInjection.agentConfig.customAttributes[]` | CustomAttributes added to each sidecar | | +| `config.infraAgentInjection.agentConfig.customAttributes[].name` | Name of custom attribute to include. | | +| `config.infraAgentInjection.agentConfig.customAttributes[].defaultValue` | Default value for custom attribute to include. | | +| `config.infraAgentInjection.agentConfig.customAttributes[].fromLabel` | Label from which take the value of the custom attribute. | | +| `config.infraAgentInjection.agentConfig.image.pullPolicy` | The sidecar image pull policy. | `IfNotPresent` | +| `config.infraAgentInjection.agentConfig.image.repository` | The infrastructure agent repository for the sidecar container. | `newrelic/infrastructure-k8s` | +| `config.infraAgentInjection.agentConfig.image.tag` | The infrastructure agent image tag for the sidecar container. | `2.8.2-unprivileged` | +| `config.infraAgentInjection.agentConfig.podSecurityContext.runAsUser` | runAsUser UID for Pod Security Context. | | +| `config.infraAgentInjection.agentConfig.podSecurityContext.runAsGroup` | runAsGroup UID for Pod Security Context. | | +| `config.infraAgentInjection.agentConfig.configSelectors[]` | 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.configSelectors[].resourceRequirements` | ResourceRequirements to apply to the sidecar. | | +| `config.infraAgentInjection.agentConfig.configSelectors[].extraEnvVars` | ExtraEnvVars to pass to the injected sidecar. | | +| `config.infraAgentInjection.agentConfig.configSelectors[].labelSelector` | LabelSelector matching the labels of the mutating pods. | | + + + +## 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/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. + +## Resources + +The default set of resources assigned to the newrelic-infra-operator pods is shown below: + +```yaml +resources: + limits: + memory: 80M + requests: + cpu: 100m + memory: 30M +``` + +The default set of resources assigned to the injected sidecar when the pod is **not** KSM is shown below: + +```yaml +resources: + limits: + memory: 100M + cpu: 200m + requests: + memory: 50M + cpu: 100m +``` + +The default set of resources assigned to the injected sidecar when the pod is KSM is shown below: + +```yaml +resources: + limits: + memory: 300M + cpu: 300m + requests: + memory: 150M + cpu: 150m +``` + +## Tolerations + +No default set of tolerations are defined. +Please note that these tolerations are applied only to the operator and the certificate-related jobs themselves, and not to any pod or container injected by it. + +[1]: https://github.com/newrelic/newrelic-infra-operator +[2]: https://cert-manager.io/ diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/ci/test-values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/ci/test-values.yaml new file mode 100644 index 000000000..3e154e1d4 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/NOTES.txt b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/NOTES.txt new file mode 100644 index 000000000..e2435385f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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 }} {{ template "newrelic-infra-operator.fullname" . }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/_helpers.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/_helpers.tpl new file mode 100644 index 000000000..27e929a86 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/_helpers.tpl @@ -0,0 +1,148 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "newrelic-infra-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 "newrelic-infra-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 "newrelic-infra-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common app label +*/}} +{{- define "newrelic-infra-operator.appLabel" -}} +app.kubernetes.io/name: {{ include "newrelic-infra-operator.name" . }} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "newrelic-infra-operator.labels" -}} +{{ include "newrelic-infra-operator.appLabel" . }} +helm.sh/chart: {{ include "newrelic-infra-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 -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "newrelic-infra-operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "newrelic-infra-operator.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the licenseKey +*/}} +{{- define "newrelic-infra-operator.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 +*/}} +{{- define "newrelic-infra-operator.cluster" -}} +{{- if .Values.global -}} + {{- if .Values.global.cluster -}} + {{- .Values.global.cluster -}} + {{- else -}} + {{- .Values.cluster | required "cluster name must be set" -}} + {{- end -}} +{{- else -}} + {{- .Values.cluster | required "cluster name must be set" -}} +{{- end -}} +{{- end -}} + +{{/* +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 -}} + +{{/* +Return the customSecretName +*/}} +{{- define "newrelic-infra-operator.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-infra-operator.customSecretLicenseKey" -}} +{{- if .Values.global }} + {{- if .Values.global.customSecretLicenseKey }} + {{- .Values.global.customSecretLicenseKey -}} + {{- else -}} + {{- .Values.customSecretLicenseKey | default "" -}} + {{- end -}} +{{- else -}} + {{- .Values.customSecretLicenseKey | default "" -}} +{{- 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 -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrole.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrole.yaml new file mode 100644 index 000000000..8fe29b030 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrole.yaml @@ -0,0 +1,25 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "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: {{ template "newrelic-infra-operator.name" $ }}-admission +{{ include "newrelic-infra-operator.labels" $ | indent 4 }} +rules: + - apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + verbs: + - get + - update + - apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "newrelic-infra-operator.fullname" . }}-admission +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/clusterrolebinding.yaml new file mode 100644 index 000000000..11981e531 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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: {{ template "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: {{ template "newrelic-infra-operator.name" $ }}-admission +{{ include "newrelic-infra-operator.labels" $ | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "newrelic-infra-operator.fullname" . }}-admission +subjects: + - kind: ServiceAccount + name: {{ template "newrelic-infra-operator.fullname" . }}-admission + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-createSecret.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-createSecret.yaml new file mode 100644 index 000000000..f5f2861f2 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-createSecret.yaml @@ -0,0 +1,54 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "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: {{ template "newrelic-infra-operator.name" $ }}-admission-create +{{ include "newrelic-infra-operator.labels" $ | indent 4 }} +spec: + template: + metadata: + name: {{ template "newrelic-infra-operator.fullname" . }}-admission-create + labels: + app: {{ template "newrelic-infra-operator.name" $ }}-admission-create +{{ include "newrelic-infra-operator.labels" $ | indent 8 }} + spec: + {{- if .Values.admissionWebhooksPatchJob.image.pullSecrets }} + imagePullSecrets: +{{ toYaml .Values.admissionWebhooksPatchJob.image.pullSecrets | indent 8 }} + {{- end }} + containers: + - name: create + image: {{ .Values.admissionWebhooksPatchJob.image.repository }}:{{ .Values.admissionWebhooksPatchJob.image.tag }} + imagePullPolicy: {{ .Values.admissionWebhooksPatchJob.image.pullPolicy }} + args: + - create + - --host={{ template "newrelic-infra-operator.fullname" . }},{{ template "newrelic-infra-operator.fullname" . }}.{{ .Release.Namespace }}.svc + - --namespace={{ .Release.Namespace }} + - --secret-name={{ template "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: {{ template "newrelic-infra-operator.fullname" . }}-admission + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + {{- if .Values.tolerations }} + tolerations: + {{- toYaml .Values.tolerations | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-patchWebhook.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-patchWebhook.yaml new file mode 100644 index 000000000..eddcd25d5 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/job-patchWebhook.yaml @@ -0,0 +1,54 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "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: {{ template "newrelic-infra-operator.name" $ }}-admission-patch +{{ include "newrelic-infra-operator.labels" $ | indent 4 }} +spec: + template: + metadata: + name: {{ template "newrelic-infra-operator.fullname" . }}-admission-patch + labels: + app: {{ template "newrelic-infra-operator.name" $ }}-admission-patch +{{ include "newrelic-infra-operator.labels" $ | indent 8 }} + spec: + {{- if .Values.admissionWebhooksPatchJob.image.pullSecrets }} + imagePullSecrets: +{{ toYaml .Values.admissionWebhooksPatchJob.image.pullSecrets | indent 8 }} + {{- end }} + containers: + - name: patch + image: {{ .Values.admissionWebhooksPatchJob.image.repository }}:{{ .Values.admissionWebhooksPatchJob.image.tag }} + imagePullPolicy: {{ .Values.admissionWebhooksPatchJob.image.pullPolicy }} + args: + - patch + - --webhook-name={{ template "newrelic-infra-operator.fullname" . }} + - --namespace={{ .Release.Namespace }} + - --secret-name={{ template "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: {{ template "newrelic-infra-operator.fullname" . }}-admission + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + {{- if .Values.tolerations }} + tolerations: + {{- toYaml .Values.tolerations | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/psp.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/psp.yaml new file mode 100644 index 000000000..cb8e939da --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/psp.yaml @@ -0,0 +1,50 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "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: {{ template "newrelic-infra-operator.name" . }}-admission +{{ include "newrelic-infra-operator.labels" . | indent 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/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/role.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/role.yaml new file mode 100644 index 000000000..fe46814bb --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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: {{ template "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: {{ template "newrelic-infra-operator.name" $ }}-admission +{{ include "newrelic-infra-operator.labels" $ | indent 4 }} +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/rolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/rolebinding.yaml new file mode 100644 index 000000000..4de6c1f2b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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: {{ template "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: {{ template "newrelic-infra-operator.name" $ }}-admission +{{ include "newrelic-infra-operator.labels" $ | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "newrelic-infra-operator.fullname" . }}-admission +subjects: + - kind: ServiceAccount + name: {{ template "newrelic-infra-operator.fullname" . }}-admission + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/serviceaccount.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/serviceaccount.yaml new file mode 100644 index 000000000..a5cabd628 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/job-patch/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "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: {{ template "newrelic-infra-operator.name" $ }}-admission +{{ include "newrelic-infra-operator.labels" $ | indent 4 }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/mutatingWebhookConfiguration.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/mutatingWebhookConfiguration.yaml new file mode 100644 index 000000000..a0f8adfc3 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/admission-webhooks/mutatingWebhookConfiguration.yaml @@ -0,0 +1,32 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ template "newrelic-infra-operator.fullname" . }} +{{- if .Values.certManager.enabled }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-root-cert" .Release.Namespace (include "newrelic-infra-operator.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-root-cert" .Release.Namespace (include "newrelic-infra-operator.fullname" .) | quote }} +{{- end }} + labels: + {{- include "newrelic-infra-operator.labels" . | nindent 4 }} +webhooks: +- name: newrelic-infra-operator.newrelic.com + clientConfig: + service: + name: {{ template "newrelic-infra-operator.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/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/cert-manager.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/cert-manager.yaml new file mode 100644 index 000000000..e92446349 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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: {{ template "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: {{ template "newrelic-infra-operator.fullname" . }}-root-cert +spec: + secretName: {{ template "newrelic-infra-operator.fullname" . }}-root-cert + duration: 43800h # 5y + issuerRef: + name: {{ template "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: {{ template "newrelic-infra-operator.fullname" . }}-root-issuer +spec: + ca: + secretName: {{ template "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: {{ template "newrelic-infra-operator.fullname" . }}-webhook-cert +spec: + secretName: {{ template "newrelic-infra-operator.fullname" . }}-admission + duration: 8760h # 1y + issuerRef: + name: {{ template "newrelic-infra-operator.fullname" . }}-root-issuer + dnsNames: + - {{ template "newrelic-infra-operator.fullname" . }} + - {{ template "newrelic-infra-operator.fullname" . }}.{{ .Release.Namespace }} + - {{ template "newrelic-infra-operator.fullname" . }}.{{ .Release.Namespace }}.svc +{{ end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/clusterrole.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/clusterrole.yaml new file mode 100644 index 000000000..8f3e408cc --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/clusterrole.yaml @@ -0,0 +1,52 @@ +{{- define "newrelic-infra-operator.infra-agent-monitoring-rules" -}} +- apiGroups: [""] + resources: + - "nodes" + - "nodes/metrics" + - "nodes/stats" + - "nodes/proxy" + - "pods" + - "services" + verbs: ["get", "list"] +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- end -}} + +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "newrelic-infra-operator.fullname" . }} + labels: + {{- include "newrelic-infra-operator.labels" . | nindent 4 }} +rules: + {{/* Allow creating and updating secrets with license key for infra agent. */ -}} + - apiGroups: [""] + resources: + - "secrets" + verbs: ["get", "update", "patch"] + resourceNames: [{{ template "newrelic-infra-operator.fullname" . }}-config] + {{/* 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: [{{ template "newrelic-infra-operator.fullname" . }}-infra-agent] + {{- /* 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: {{ template "newrelic-infra-operator.fullname" . }}-infra-agent + labels: {{- include "newrelic-infra-operator.labels" . | nindent 4 }} +rules: + {{- include "newrelic-infra-operator.infra-agent-monitoring-rules" . | nindent 2 }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..c58df7feb --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/clusterrolebinding.yaml @@ -0,0 +1,26 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "newrelic-infra-operator.fullname" . }} + labels: + {{- include "newrelic-infra-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "newrelic-infra-operator.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "newrelic-infra-operator.serviceAccountName" . }} + 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: {{ template "newrelic-infra-operator.fullname" . }}-infra-agent + labels: + {{- include "newrelic-infra-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "newrelic-infra-operator.fullname" . }}-infra-agent diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/configmap.yaml new file mode 100644 index 000000000..ed3f02a03 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/configmap.yaml @@ -0,0 +1,35 @@ +{{- define "fargate-config" -}} +infraAgentInjection: + resourcePrefix: {{ template "newrelic-infra-operator.fullname" . }} +{{- if include "newrelic.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 -}} + +{{- define "config" -}} +{{ toYaml (merge (include "fargate-config" . | fromYaml) .Values.config) }} +{{- end }} + +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "newrelic-infra-operator.fullname" . }}-config + labels: + {{- include "newrelic-infra-operator.labels" . | nindent 4 }} +data: + operator.yaml: {{- include "config" . | toYaml | nindent 4 }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/deployment.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/deployment.yaml new file mode 100644 index 000000000..79b2d55a6 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/deployment.yaml @@ -0,0 +1,90 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "newrelic-infra-operator.fullname" . }} + labels: + {{- include "newrelic-infra-operator.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + {{- include "newrelic-infra-operator.appLabel" . | 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-infra-operator.labels" . | nindent 8 }} + spec: + serviceAccountName: {{ template "newrelic-infra-operator.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: + runAsUser: {{ .Values.podSecurityContext.runAsUser }} + runAsGroup: {{ .Values.podSecurityContext.runAsGroup }} + fsGroup: {{ .Values.podSecurityContext.fsGroup }} + {{- end }} + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- toYaml .Values.image.pullSecrets | nindent 8 }} + {{- end }} + containers: + - name: {{ template "newrelic-infra-operator.name" . }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + env: + - name: CLUSTER_NAME + value: {{ include "newrelic-infra-operator.cluster" . }} + - name: NRIA_LICENSE_KEY + valueFrom: + secretKeyRef: + {{- if (include "newrelic-infra-operator.licenseKey" .) }} + name: {{ template "newrelic-infra-operator.fullname" . }}-license + key: license + {{- else if include "newrelic-infra-operator.customSecretName" . }} + name: {{ include "newrelic-infra-operator.customSecretName" . }} + key: {{ include "newrelic-infra-operator.customSecretLicenseKey" . }} + {{- else }} + {{- "" | required "Cannot find License Key, either licenseKey or customSecretName must be defined" }} + {{- end }} + 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: {{ template "newrelic-infra-operator.fullname" . }}-config + - name: tls-key-cert-pair + secret: + secretName: {{ template "newrelic-infra-operator.fullname" . }}-admission + {{- if $.Values.priorityClassName }} + priorityClassName: {{ $.Values.priorityClassName }} + {{- 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 }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/secret.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/secret.yaml new file mode 100644 index 000000000..be99252ed --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/secret.yaml @@ -0,0 +1,13 @@ +{{- $licenseKey := include "newrelic-infra-operator.licenseKey" . -}} +{{- if $licenseKey }} +apiVersion: v1 +kind: Secret +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "newrelic-infra-operator.fullname" . }}-license + labels: +{{ include "newrelic-infra-operator.labels" . | indent 4 }} +type: Opaque +data: + license: {{ $licenseKey | b64enc }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/service.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/service.yaml new file mode 100644 index 000000000..175cc9992 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "newrelic-infra-operator.fullname" . }} + labels: + {{- include "newrelic-infra-operator.labels" . | nindent 4 }} +spec: + ports: + - port: 443 + targetPort: 9443 + selector: + {{- include "newrelic-infra-operator.appLabel" . | nindent 4 }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/serviceaccount.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/serviceaccount.yaml new file mode 100644 index 000000000..2da1380f0 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/templates/serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ template "newrelic-infra-operator.serviceAccountName" . }} + labels: + {{- include "newrelic-infra-operator.labels" . | nindent 4 }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/values.yaml new file mode 100644 index 000000000..7fc001b93 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infra-operator/values.yaml @@ -0,0 +1,190 @@ +# IMPORTANT: The Kubernetes cluster name +# https://docs.newrelic.com/docs/kubernetes-monitoring-integration +# +# licenseKey: +# cluster: +# fargate: +# 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: +# fargate + +image: + repository: newrelic/newrelic-infra-operator + tag: "" # Defaults to AppVersion + pullPolicy: IfNotPresent +# It is possible to specify docker registry credentials. +# See https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod +# pullSecrets: +# - name: regsecret + +admissionWebhooksPatchJob: + image: + repository: k8s.gcr.io/ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + pullPolicy: IfNotPresent +# 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: {} + +replicas: 1 + +resources: + limits: + memory: 80M + requests: + cpu: 100m + memory: 30M + +serviceAccount: +# Specifies whether a ServiceAccount should be created for the job and the deployment. + 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: + +# Configure podSecurityContext +podSecurityContext: + enabled: false + fsGroup: 1001 + runAsUser: 1001 + runAsGroup: 1001 + +# Use cert manager for webhook certs, rather than the built-in patch job. +certManager: + enabled: false + +# If you wish to provide additional annotations to apply to the pod(s), specify them here. +# podAnnotations: + +# Pod scheduling priority +# Ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +# priorityClassName: high-priority + +# Webhook timeout. +# Configure how long the API server should wait for a webhook to respond before treating the call as a failure. +# Ref: https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#timeouts +timeoutSeconds: 30 + +# Operator configuration +# The following are the default values for the operator +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 + infraAgentInjection: +## 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 + agentConfig: +## CustomAttributes 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. + image: + repository: newrelic/infrastructure-k8s + tag: 2.8.2-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. + configSelectors: +## resourceRequirements to apply to the injected sidecar. + - resourceRequirements: + limits: + memory: 100M + cpu: 200m + requests: + memory: 50M + cpu: 100m +## extraEnvVars to pass to the injected sidecar. + extraEnvVars: + 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: + +fullnameOverride: "" +affinity: {} +tolerations: [] diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/.helmignore b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/.helmignore new file mode 100644 index 000000000..2bfa6a4d9 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/.helmignore @@ -0,0 +1 @@ +tests/ diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/Chart.lock b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/Chart.lock new file mode 100644 index 000000000..f6903774c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.0.2 +digest: sha256:22d56c5e643d46e9a1675354595ca6832a0f4db8422d89cb7db73a3b0d0d7873 +generated: "2022-04-22T16:59:10.493566+02:00" diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/Chart.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/Chart.yaml new file mode 100644 index 000000000..fde66a48f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/Chart.yaml @@ -0,0 +1,36 @@ +apiVersion: v2 +appVersion: 3.1.1 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.0.2 +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: 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-infrastructure +sources: +- https://github.com/newrelic/nri-kubernetes/ +- https://github.com/newrelic/nri-kubernetes/tree/master/charts/newrelic-infrastructure +- https://github.com/newrelic/infrastructure-agent/ +version: 3.3.3 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/README.md b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/README.md new file mode 100644 index 000000000..1aa1d72b8 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/README.md @@ -0,0 +1,209 @@ +# newrelic-infrastructure + +![Version: 3.3.3](https://img.shields.io/badge/Version-3.3.3-informational?style=flat-square) ![AppVersion: 3.1.1](https://img.shields.io/badge/AppVersion-3.1.1-informational?style=flat-square) + +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 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. | +| 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.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. | +| 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` | +| 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 control plane DaemonSet. | +| ksm.config.retries | int | `3` | Number of retries after timeout expired | +| 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.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 | Affinity for the control plane DaemonSet. | +| kubelet | object | See `values.yaml` | Configuration for the DaemonSet that collects metrics from the Kubelet. | +| kubelet.config.retries | int | `3` | Number of retries after timeout expired | +| 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.tolerations | list | Schedules in all tainted nodes | Affinity 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 | object | `{"create":true,"pspEnabled":false}` | Settings controlling RBAC objects creation. | +| 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. | +| 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. | +| 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 DaemonSets deployed. | +| 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) + +## 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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/README.md.gotmpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/README.md.gotmpl new file mode 100644 index 000000000..a8acb6d5f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/README.md.gotmpl @@ -0,0 +1,139 @@ +{{ 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-kubernetes https://newrelic.github.io/nri-kubernetes +helm upgrade --install 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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/.helmignore b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/Chart.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/Chart.yaml new file mode 100644 index 000000000..5844b1e63 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: alvarocabanas + url: https://github.com/alvarocabanas +- name: carlossscastro + url: https://github.com/carlossscastro +- 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: sigilioso + url: https://github.com/sigilioso +name: common-library +type: library +version: 1.0.2 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_affinity.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_agent-config.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..c2fc46817 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,25 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +verbose: 1 +{{- 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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_cluster.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_custom-attributes.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_dnsconfig.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_fedramp.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_hostnetwork.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_images.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..43f657ad2 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_images.tpl @@ -0,0 +1,85 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "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 "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} + {{- if .imageRoot.registry -}} + {{- .imageRoot.registry -}} + {{- else if .context.Values.global -}} + {{- if .context.Values.global.image -}} + {{- with .context.Values.global.image.registry -}} + {{- . -}} + {{- end -}} + {{- end -}} + {{- 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.image.pullSecrets1, .Values.path.to.the.image.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.image -}} + {{- if .context.Values.global.image.pullSecrets -}} + {{- range .context.Values.global.image.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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_labels.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_license.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..d1ec88e49 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_license.tpl @@ -0,0 +1,55 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{ include "newrelic.common.license._customSecretName" . | default (printf "%s-license" (include "newrelic.common.naming.fullname" . )) }} +{{- 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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_license_secret.yaml.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_low-data-mode.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_naming.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..653b90b9b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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.trucateToDNS" -}} +{{- . | 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.trucateToDNS" .suffix) -}} +{{- $maxLen := (sub 63 (len $suffix)) -}} + +{{- $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.trucateToDNS" $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.trucateToDNS" $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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_nodeselector.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_priority-class-name.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_privileged.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_proxy.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_security-context.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_serviceaccount.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..14711398e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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-logging.serviceAccount" .)`, 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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_staging.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_tolerations.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_verbose-log.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/ci/test-cplane-kind-deployment-values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/ci/test-cplane-kind-deployment-values.yaml new file mode 100644 index 000000000..1e2c36d21 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/ci/test-values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/ci/test-values.yaml new file mode 100644 index 000000000..125a49607 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/NOTES.txt b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/NOTES.txt new file mode 100644 index 000000000..16cc6ea13 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/_helpers.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/_helpers.tpl new file mode 100644 index 000000000..618311b77 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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.trucateToDNS" $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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/_helpers_compatibility.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/_helpers_compatibility.tpl new file mode 100644 index 000000000..77c892592 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/_helpers_compatibility.tpl @@ -0,0 +1,199 @@ +{{/* +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" -}} +{{ $config:= (include "newrelic.compatibility.valueWithFallback" (dict "legacy" .Values.config "supported" .Values.common.agentConfig ) | fromYaml )}} +{{- if .Values.eventQueueDepth -}} +{{- mustMergeOverwrite $config (dict "event_queue_depth" .Values.eventQueueDepth ) | toYaml }} +{{- else -}} +{{- $config | toYaml }} +{{- end -}} +{{- 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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/clusterrole.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/clusterrole.yaml new file mode 100644 index 000000000..74c032883 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/clusterrole.yaml @@ -0,0 +1,33 @@ +{{- 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" + 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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..fc5dfb8da --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_affinity_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_affinity_helper.tpl new file mode 100644 index 000000000..320d16dae --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_agent-config_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_agent-config_helper.tpl new file mode 100644 index 000000000..721c4424c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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 +overide_host_root: "" # Typo from here: https://github.com/newrelic/infrastructure-agent/blob/master/pkg/config/config.go#L267 +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" . ) -}} +{{- $customAttributes := dict "custom_attributes" (dict "clusterName" (include "newrelic.common.cluster" . )) -}} + +{{- mustMergeOverwrite $agentDefaults $controlPlane $agentConfig $customAttributes | toYaml -}} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_host_network.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_host_network.tpl new file mode 100644 index 000000000..2f3bdf2d9 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_naming.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_naming.tpl new file mode 100644 index 000000000..7e651426b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_naming.tpl @@ -0,0 +1,8 @@ +{{- /* 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 -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_rbac.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_rbac.tpl new file mode 100644 index 000000000..a279df6b4 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_tolerations_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/_tolerations_helper.tpl new file mode 100644 index 000000000..3c82e82f5 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/agent-configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/agent-configmap.yaml new file mode 100644 index 000000000..77f2e11dd --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/clusterrole.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/clusterrole.yaml new file mode 100644 index 000000000..57633e7f7 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/clusterrolebinding.yaml new file mode 100644 index 000000000..263381a1b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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 "newrelic.common.serviceAccount.name" . }}-controlplane + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/daemonset.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/daemonset.yaml new file mode 100644 index 000000000..9d558cbc1 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/daemonset.yaml @@ -0,0 +1,202 @@ +{{- 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 }} + 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 "newrelic.common.serviceAccount.name" . }}-controlplane + + {{- 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_OVERRIDE_HOSTNAME_SHORT" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + + - 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 }} + {{- with .Values.controlPlane.nodeSelector | default (fromYaml (include "newrelic.common.nodeSelector" .)) }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end -}} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/rolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/rolebinding.yaml new file mode 100644 index 000000000..cb37a4b2a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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 "newrelic.common.serviceAccount.name" $ }}-controlplane + namespace: {{ $.Release.Namespace }} +{{- end -}} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/scraper-configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/scraper-configmap.yaml new file mode 100644 index 000000000..454665ded --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/serviceaccount.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/controlplane/serviceaccount.yaml new file mode 100644 index 000000000..8e9fecfc4 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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 "newrelic.common.serviceAccount.name" . }}-controlplane + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_affinity_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_affinity_helper.tpl new file mode 100644 index 000000000..ce795708d --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_agent-config_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_agent-config_helper.tpl new file mode 100644 index 000000000..b3f13ba85 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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 +overide_host_root: "" # Typo from here: https://github.com/newrelic/infrastructure-agent/blob/master/pkg/config/config.go#L267 +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" . ) -}} +{{- $customAttributes := dict "custom_attributes" (dict "clusterName" (include "newrelic.common.cluster" . )) -}} + +{{- mustMergeOverwrite $agentDefaults $ksm $agentConfig $customAttributes | toYaml -}} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_naming.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_naming.tpl new file mode 100644 index 000000000..d8c283c43 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_tolerations_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/_tolerations_helper.tpl new file mode 100644 index 000000000..e1a9fd80c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/agent-configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/agent-configmap.yaml new file mode 100644 index 000000000..6a438e9a3 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/deployment.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/deployment.yaml new file mode 100644 index 000000000..64d889b3f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/deployment.yaml @@ -0,0 +1,191 @@ +{{- 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: + 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 "newrelic.common.hostNetwork.value" . }} + {{- if include "nriKubernetes.controlPlane.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_OVERRIDE_HOSTNAME_SHORT" + valueFrom: + fieldRef: + apiVersion: "v1" + fieldPath: "spec.nodeName" + + - 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 }} + {{- with .Values.ksm.nodeSelector | default (fromYaml (include "newrelic.common.nodeSelector" .)) }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end -}} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/scraper-configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/scraper-configmap.yaml new file mode 100644 index 000000000..a2f48a3a5 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/ksm/scraper-configmap.yaml @@ -0,0 +1,16 @@ +{{- 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: + {{- /* Notice that new values takes precedence since they have no default and the user need to set them up specifically*/ -}} + {{- mustMergeOverwrite (include "newrelic.compatibility.ksm.legacyData" . | fromYaml) .Values.ksm.config | toYaml | nindent 6 -}} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_affinity_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_affinity_helper.tpl new file mode 100644 index 000000000..a3abf0855 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_agent-config_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_agent-config_helper.tpl new file mode 100644 index 000000000..7777955e5 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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 +overide_host_root: "" # Typo from here: https://github.com/newrelic/infrastructure-agent/blob/master/pkg/config/config.go#L267 +{{- 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" . ) -}} +{{- $customAttributes := dict "custom_attributes" (dict "clusterName" (include "newrelic.common.cluster" . )) -}} + +{{- mustMergeOverwrite $agentDefaults $kubelet $agentConfig $customAttributes | toYaml -}} +{{- end -}} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_naming.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_naming.tpl new file mode 100644 index 000000000..71c142156 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_security_context_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_security_context_helper.tpl new file mode 100644 index 000000000..4e334466c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_tolerations_helper.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/_tolerations_helper.tpl new file mode 100644 index 000000000..e46d83d69 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/agent-configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/agent-configmap.yaml new file mode 100644 index 000000000..0f71f129a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/daemonset.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/daemonset.yaml new file mode 100644 index 000000000..4e1aed524 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/daemonset.yaml @@ -0,0 +1,245 @@ +{{- 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 "newrelic.common.hostNetwork.value" . }} + {{- if include "nriKubernetes.controlPlane.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: "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-docker-socket + mountPath: /var/run/docker.sock + - name: log + mountPath: /var/log + - name: host-volume + mountPath: /host + 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-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 }} + {{- with .Values.kubelet.nodeSelector | default (fromYaml (include "newrelic.common.nodeSelector" .)) }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end -}} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/integrations-configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/integrations-configmap.yaml new file mode 100644 index 000000000..17d626c7c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/integrations-configmap.yaml @@ -0,0 +1,37 @@ +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: |- + {{- tpl ($v | toYaml) $ | nindent 4 -}} + {{- end }} + {{- end }} + {{- include "newrelic.compatibility.integrations" . | nindent 2 }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/scraper-configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/kubelet/scraper-configmap.yaml new file mode 100644 index 000000000..e43b5227f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/podsecuritypolicy.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..5b5058511 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/secret.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/secret.yaml new file mode 100644 index 000000000..f558ee86c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/serviceaccount.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/templates/serviceaccount.yaml new file mode 100644 index 000000000..f987cc512 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/values.yaml new file mode 100644 index 000000000..db412db6a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-infrastructure/values.yaml @@ -0,0 +1,514 @@ +# -- 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: + pullPolicy: IfNotPresent + tag: 1.24.1 + repository: newrelic/k8s-events-forwarder + registry: "" + # -- Image for the New Relic Infrastructure Agent plus integrations. + # @default -- See `values.yaml` + agent: + pullPolicy: IfNotPresent + tag: 2.8.8 + repository: newrelic/infrastructure-bundle + registry: "" + # -- Image for the New Relic Kubernetes integration. + # @default -- See `values.yaml` + integration: + pullPolicy: IfNotPresent + tag: 3.1.0 + repository: newrelic/nri-kubernetes + registry: "" + +# -- 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 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: + +# 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: {} + # -- Affinity for the control plane DaemonSet. + # @default -- Schedules in all tainted nodes + tolerations: + - operator: "Exists" + effect: "NoSchedule" + - operator: "Exists" + effect: "NoExecute" + nodeSelector: {} + affinity: {} + extraEnv: [] + extraEnvFrom: [] + 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 + # 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: {} + # -- Affinity 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 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 + 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" + # -- the URL scheme is not discovered and the specified one is used + # scheme: "http" + # -- the port is not discovered and the specified one is used + # port: 8080 + # -- only the pods matching this selector are taken into account during autodiscovery + # selector: "app.kubernetes.io/name=kube-state-metrics" + # -- only the pods matching this namespace taken into account during autodiscovery + # namespace: "ksm-namespace" + +# controlPlane -- Configuration for the control plane scraper. +# @default -- See `values.yaml` +controlPlane: + # -- Deploy control plane monitoring component. + enabled: true + annotations: {} + 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 + 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: "k8s-app=etcd" + # namespace: kube-system + # 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: 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: kube-system + matchNode: true + endpoints: + - url: https://localhost:10257 + insecureSkipVerify: true + auth: + type: bearer + # mtls: + # secretName: secret-name + # secretNamespace: secret-namespace + - selector: "app=controller-manager,controller-manager=true" + namespace: kube-system + matchNode: true + endpoints: + - url: https://localhost:10257 + 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: {} + + # -- 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: 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 DaemonSets deployed. +# @default -- See `values.yaml` +updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + +# -- 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: + # -- 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 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: + # -- 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: [] + +# -- 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 key must end in ".yaml" as this will be the +# filename generated and the Infrastructure agent only looks for YAML files. +# 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 + +# Collect detailed metrics from processes running in the host. +# @default -- [True only for accounts created before July 20, 2020.](https://docs.newrelic.com/docs/release-notes/infrastructure-release-notes/infrastructure-agent-release-notes/new-relic-infrastructure-agent-1120) +# enableProcessMetrics: false + +# Send data to New Relic Staging. Requires an staging-specific License Key. +# nrStaging: false + +# 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 + + +# -- 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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/.helmignore b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/.helmignore new file mode 100644 index 000000000..1ed4e226e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/Chart.lock b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/Chart.lock new file mode 100644 index 000000000..33d1a0707 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.0.2 +digest: sha256:22d56c5e643d46e9a1675354595ca6832a0f4db8422d89cb7db73a3b0d0d7873 +generated: "2022-04-21T12:45:30.433112+02:00" diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/Chart.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/Chart.yaml new file mode 100644 index 000000000..e0c500a7a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +appVersion: 0.2.0 +dependencies: +- name: common-library + repository: https://helm-charts.newrelic.com + version: 1.0.2 +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: alvarocabanas +- name: carlossscastro +- name: gsanchezgavier +- name: kang-makes +- name: marcsanmi +- name: paologallinaharbur +- name: roobre +- name: sigilioso +name: newrelic-k8s-metrics-adapter +sources: +- https://github.com/newrelic/newrelic-k8s-metrics-adapter +version: 0.7.4 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/README.md b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/README.md new file mode 100644 index 000000000..988088fb5 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/README.md @@ -0,0 +1,143 @@ +[![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 + +![Version: 0.7.4](https://img.shields.io/badge/Version-0.7.4-informational?style=flat-square) ![AppVersion: 0.2.0](https://img.shields.io/badge/AppVersion-0.2.0-informational?style=flat-square) + +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.0.2 | + +## 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.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. | +| 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/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 + +* alvarocabanas +* carlossscastro +* gsanchezgavier +* kang-makes +* marcsanmi +* paologallinaharbur +* roobre +* sigilioso diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/README.md.gotmpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/README.md.gotmpl new file mode 100644 index 000000000..5ba4e6f6f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/README.md.gotmpl @@ -0,0 +1,109 @@ +[![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.badgesSection" . }} + +{{ 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/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/.helmignore b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/Chart.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/Chart.yaml new file mode 100644 index 000000000..5844b1e63 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/Chart.yaml @@ -0,0 +1,25 @@ +apiVersion: v2 +description: Provides helpers to provide consistency on all the charts +keywords: +- newrelic +- chart-library +maintainers: +- name: alvarocabanas + url: https://github.com/alvarocabanas +- name: carlossscastro + url: https://github.com/carlossscastro +- 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: sigilioso + url: https://github.com/sigilioso +name: common-library +type: library +version: 1.0.2 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_affinity.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_affinity.tpl new file mode 100644 index 000000000..1b2636754 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_agent-config.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_agent-config.tpl new file mode 100644 index 000000000..c2fc46817 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_agent-config.tpl @@ -0,0 +1,25 @@ +{{/* +This helper should return the defaults that all agents should have +*/}} +{{- define "newrelic.common.agentConfig.defaults" -}} +{{- if include "newrelic.common.verboseLog" . }} +verbose: 1 +{{- 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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_cluster.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_cluster.tpl new file mode 100644 index 000000000..0197dd35a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_custom-attributes.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_custom-attributes.tpl new file mode 100644 index 000000000..92020719c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_dnsconfig.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_dnsconfig.tpl new file mode 100644 index 000000000..d4e40aa8a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_fedramp.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_fedramp.tpl new file mode 100644 index 000000000..9df8d6b5e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_hostnetwork.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_hostnetwork.tpl new file mode 100644 index 000000000..4cf017ef7 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_images.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_images.tpl new file mode 100644 index 000000000..43f657ad2 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_images.tpl @@ -0,0 +1,85 @@ +{{- /* +Return the proper image name +{{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.path.to.the.image "context" .) }} +*/ -}} +{{- define "newrelic.common.images.image" -}} + {{- $registryName := include "newrelic.common.images.registry" ( dict "imageRoot" .imageRoot "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 "context" .) }} +*/ -}} +{{- define "newrelic.common.images.registry" -}} + {{- if .imageRoot.registry -}} + {{- .imageRoot.registry -}} + {{- else if .context.Values.global -}} + {{- if .context.Values.global.image -}} + {{- with .context.Values.global.image.registry -}} + {{- . -}} + {{- end -}} + {{- end -}} + {{- 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.image.pullSecrets1, .Values.path.to.the.image.pullSecrets2) "context" .) }} +*/ -}} +{{- define "newrelic.common.images.renderPullSecrets" -}} + {{- $flatlist := list }} + + {{- if .context.Values.global -}} + {{- if .context.Values.global.image -}} + {{- if .context.Values.global.image.pullSecrets -}} + {{- range .context.Values.global.image.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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_labels.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_labels.tpl new file mode 100644 index 000000000..b02594828 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license.tpl new file mode 100644 index 000000000..d1ec88e49 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license.tpl @@ -0,0 +1,55 @@ +{{/* +Return the name of the secret holding the License Key. +*/}} +{{- define "newrelic.common.license.secretName" -}} +{{ include "newrelic.common.license._customSecretName" . | default (printf "%s-license" (include "newrelic.common.naming.fullname" . )) }} +{{- 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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license_secret.yaml.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_license_secret.yaml.tpl new file mode 100644 index 000000000..610a0a337 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_low-data-mode.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_low-data-mode.tpl new file mode 100644 index 000000000..3dd55ef2f --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_naming.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_naming.tpl new file mode 100644 index 000000000..653b90b9b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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.trucateToDNS" -}} +{{- . | 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.trucateToDNS" .suffix) -}} +{{- $maxLen := (sub 63 (len $suffix)) -}} + +{{- $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.trucateToDNS" $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.trucateToDNS" $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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_nodeselector.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_nodeselector.tpl new file mode 100644 index 000000000..d48887341 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_priority-class-name.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_priority-class-name.tpl new file mode 100644 index 000000000..50182b734 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_privileged.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_privileged.tpl new file mode 100644 index 000000000..f3ae814dd --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_proxy.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_proxy.tpl new file mode 100644 index 000000000..60f34c7ec --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_security-context.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_security-context.tpl new file mode 100644 index 000000000..9edfcabfd --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_serviceaccount.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_serviceaccount.tpl new file mode 100644 index 000000000..14711398e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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-logging.serviceAccount" .)`, 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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_staging.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_staging.tpl new file mode 100644 index 000000000..bd9ad09bb --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_tolerations.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_tolerations.tpl new file mode 100644 index 000000000..e016b38e2 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_verbose-log.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/templates/_verbose-log.tpl new file mode 100644 index 000000000..2286d4681 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/charts/common-library/values.yaml new file mode 100644 index 000000000..75e2d112a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/ci/test-values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/ci/test-values.yaml new file mode 100644 index 000000000..aa2c48c09 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/ci/test-values.yaml @@ -0,0 +1,49 @@ +global: + cluster: test-cluster + +personalAPIKey: "a21321" +verboseLog: false + +config: + accountID: 111 + region: EU + +extraEnv: + - name: ENV_VAR1 + value: "var1" + - name: ENV_VAR2 + value: "var2" +extraVolumes: + - name: tmpfs-data + emptyDir: {} +extraVolumeMounts: + - mountPath: /var/db/newrelic-infra/data + name: tmpfs-data +hostNetwork: true +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 + +apiServicePatchJob: + volumes: + - name: tmpfs-data + emptyDir: {} + volumeMounts: + - mountPath: /var/db/newrelic-infra/data + name: tmpfs-data + +image: + repository: e2e/newrelic-metrics-adapter + tag: "test" # Defaults to AppVersion diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/_helpers.tpl b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/_helpers.tpl new file mode 100644 index 000000000..e1b546683 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/_helpers.tpl @@ -0,0 +1,49 @@ +{{/* 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-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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/adapter-clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/adapter-clusterrolebinding.yaml new file mode 100644 index 000000000..40bcba8b6 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/adapter-rolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/adapter-rolebinding.yaml new file mode 100644 index 000000000..afb5d2d55 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/apiservice.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/apiservice.yaml new file mode 100644 index 000000000..8f01b6407 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrole.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrole.yaml new file mode 100644 index 000000000..29c733c29 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrole.yaml @@ -0,0 +1,24 @@ +{{- 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 + - apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ include "newrelic-k8s-metrics-adapter.name.apiservice" . }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/clusterrolebinding.yaml new file mode 100644 index 000000000..8f6a8feff --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-createSecret.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-createSecret.yaml new file mode 100644 index 000000000..f375ebaf8 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-createSecret.yaml @@ -0,0 +1,52 @@ +{{- 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 "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" . }} + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-patchAPIService.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-patchAPIService.yaml new file mode 100644 index 000000000..78173923a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/job-patchAPIService.yaml @@ -0,0 +1,50 @@ +{{- 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 "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" . }} + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + {{- with include "newrelic.common.tolerations" . }} + tolerations: + {{- . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/psp.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/psp.yaml new file mode 100644 index 000000000..5efde0fd6 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/psp.yaml @@ -0,0 +1,49 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/role.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/role.yaml new file mode 100644 index 000000000..1e870e082 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/rolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/rolebinding.yaml new file mode 100644 index 000000000..588b4db1e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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" . }} + namespace: {{ .Release.Namespace }} +{{- end }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/serviceaccount.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/serviceaccount.yaml new file mode 100644 index 000000000..ada41d4eb --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/apiservice/job-patch/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if (and (not .Values.customTLSCertificate) (not .Values.certManager.enabled)) }} +apiVersion: v1 +kind: ServiceAccount +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 + # 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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/configmap.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/configmap.yaml new file mode 100644 index 000000000..adf4f2747 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/configmap.yaml @@ -0,0 +1,18 @@ +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 }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/deployment.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/deployment.yaml new file mode 100644 index 000000000..d7aba6320 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/deployment.yaml @@ -0,0 +1,114 @@ +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" . | 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 }} + {{- with include "newrelic.common.nodeSelector" . }} + nodeSelector: + {{- . | nindent 8 }} + {{- end }} + {{- 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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrole.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrole.yaml new file mode 100644 index 000000000..402fece01 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrolebinding.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/hpa-clusterrolebinding.yaml new file mode 100644 index 000000000..390fab452 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/secret.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/secret.yaml new file mode 100644 index 000000000..09a70ab65 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/service.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/service.yaml new file mode 100644 index 000000000..82015830c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/serviceaccount.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/serviceaccount.yaml new file mode 100644 index 000000000..4a37c9c67 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/templates/serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: {{ .Release.Namespace }} + name: {{ include "newrelic.common.serviceAccount.name" . }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/apiservice_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/apiservice_test.yaml new file mode 100644 index 000000000..3793d3365 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/apiservice_test.yaml @@ -0,0 +1,18 @@ +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: Anotations are correctly defined + set: + 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/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/common_extra_naming_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/common_extra_naming_test.yaml new file mode 100644 index 000000000..1c6fdbf96 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/common_extra_naming_test.yaml @@ -0,0 +1,24 @@ +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: + personalAPIKey: 21321 + config: + accountID: 11111111 + asserts: + - matchRegex: + path: metadata.name + pattern: ^.*(-apiservice|-hpa-controller|:external-metrics|:system:auth-delegator) diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/configmap_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/configmap_test.yaml new file mode 100644 index 000000000..28c8472c0 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/configmap_test.yaml @@ -0,0 +1,92 @@ +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 + config: + accountID: 111 + region: A-REGION + asserts: + - equal: + path: data.config\.yaml + value: | + accountID: 111 + region: A-REGION + cacheTTLSeconds: 30 + - it: has the correct region when global staging + set: + personalAPIKey: 21321 + config: + accountID: 111 + global: + nrStaging: true + asserts: + - equal: + path: data.config\.yaml + value: | + accountID: 111 + region: Staging + cacheTTLSeconds: 30 + - it: has the correct region when global values and licenseKey is from eu + set: + personalAPIKey: 21321 + licenseKey: eu-whatever + config: + accountID: 111 + global: + aRandomGlobalValue: true + asserts: + - equal: + path: data.config\.yaml + value: | + accountID: 111 + region: EU + cacheTTLSeconds: 30 + - it: has the correct region when no global values exist and licenseKey is from eu + set: + personalAPIKey: 21321 + licenseKey: eu-whatever + config: + accountID: 111 + asserts: + - equal: + path: data.config\.yaml + value: | + accountID: 111 + region: EU + cacheTTLSeconds: 30 + - it: has no region when not defined and licenseKey is not from eu + set: + personalAPIKey: 21321 + licenseKey: us-whatever + config: + accountID: 111 + asserts: + - equal: + path: data.config\.yaml + value: | + accountID: 111 + cacheTTLSeconds: 30 + - it: has externalMetrics when defined + set: + personalAPIKey: 21321 + 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) diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/deployment_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/deployment_test.yaml new file mode 100644 index 000000000..e983a7519 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/deployment_test.yaml @@ -0,0 +1,68 @@ +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 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/hpa_clusterrolebinding_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/hpa_clusterrolebinding_test.yaml new file mode 100644 index 000000000..c1db71af7 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/hpa_clusterrolebinding_test.yaml @@ -0,0 +1,12 @@ +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 + asserts: + - matchRegex: + path: roleRef.name + pattern: ^.*:external-metrics diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_cluster_rolebinding_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_cluster_rolebinding_test.yaml new file mode 100644 index 000000000..7e9c99b9e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_cluster_rolebinding_test.yaml @@ -0,0 +1,16 @@ +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 + asserts: + - matchRegex: + path: roleRef.name + pattern: ^.*-apiservice + - matchRegex: + path: subjects[0].name + pattern: ^.*-apiservice diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_clusterrole_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_clusterrole_test.yaml new file mode 100644 index 000000000..3f56a9a73 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_clusterrole_test.yaml @@ -0,0 +1,12 @@ +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 + asserts: + - matchRegex: + path: rules[1].resourceNames[0] + pattern: ^.*-apiservice diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_common_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_common_test.yaml new file mode 100644 index 000000000..0bc04371c --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_common_test.yaml @@ -0,0 +1,22 @@ +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: + customTLSCertificate: a-tls-cert + certManager: + enabled: true + asserts: + - hasDocuments: + count: 0 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_createsecret_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_createsecret_test.yaml new file mode 100644 index 000000000..78c25b15b --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_createsecret_test.yaml @@ -0,0 +1,31 @@ +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 + asserts: + - equal: + path: spec.template.metadata.name + value: my-release-newrelic-k8s-metrics-adapter-apiservice-create + - it: container args are correctly defined + 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: + personalAPIKey: 21321 + apiServicePatchJob: + image: + repository: k8s.gcr.io/ingress-nginx/kube-webhook-certgen + tag: "latest" + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: ^.*k8s.gcr.io/ingress-nginx/kube-webhook-certgen:latest diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_patchapiservice_test.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_patchapiservice_test.yaml new file mode 100644 index 000000000..9fffe715e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/tests/job_patch_job_patchapiservice_test.yaml @@ -0,0 +1,34 @@ +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 + asserts: + - matchRegex: + path: spec.template.metadata.name + pattern: .*-apiservice-patch$ + - it: container args are correctly defined + asserts: + - matchRegex: + path: spec.template.spec.containers[0].args[2] + pattern: ^--secret-name=.*-apiservice + + - it: serviceAccountName is correctly defined + asserts: + - matchRegex: + path: spec.template.spec.serviceAccountName + pattern: .*-apiservice$ + - it: has the correct image + set: + personalAPIKey: 21321 + apiServicePatchJob: + image: + repository: k8s.gcr.io/ingress-nginx/kube-webhook-certgen + tag: "latest" + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: .*k8s.gcr.io/ingress-nginx/kube-webhook-certgen:latest$ diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/values.yaml new file mode 100644 index 000000000..a19d1d9e6 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-k8s-metrics-adapter/values.yaml @@ -0,0 +1,148 @@ +# 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 + +# 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: k8s.gcr.io + repository: ingress-nginx/kube-webhook-certgen + tag: v1.1.1 + 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 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/Chart.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/Chart.yaml new file mode 100644 index 000000000..202b687af --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +appVersion: 1.10.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: tejunior +- name: jodstrcil +- name: edmocosta +- name: Noly +- name: danybmx +name: newrelic-logging +version: 1.10.9 diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/README.md b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/README.md new file mode 100644 index 000000000..b706c2d3a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/README.md @@ -0,0 +1,216 @@ +# 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, either using a [Helm](https://helm.sh/) chart (recommended), or manually by applying Kubernetes manifests. + +## Installation + +### Install using the Helm chart (recommended) + + 1. Install Helm following the [official instructions](https://helm.sh/docs/intro/install/). + + 2. Add the New Relic official Helm chart repository following [these instructions](../../README.md#installing-charts) + + 3. Run the following command to install the New Relic Logging Kubernetes plugin via Helm, replacing the placeholder value `YOUR_LICENSE_KEY` with your [New Relic license key](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/license-key): + * Helm 3 + ```sh + helm install newrelic-logging newrelic/newrelic-logging --set licenseKey=YOUR_LICENSE_KEY + ``` + * Helm 2 + ```sh + helm install newrelic/newrelic-logging --name newrelic-logging --set licenseKey=YOUR_LICENSE_KEY + ``` + +> For EU users, add `--set endpoint=https://log-api.eu.newrelic.com/log/v1 to any of the helm install commands above. + +> By default, tailing is set to `/var/log/containers/*.log`. To change this setting, provide your preferred path by adding `--set fluentBit.path=DESIRED_PATH` to any of the helm install commands above. + +### Install the Kubernetes manifests manually + + 1. Download the following 3 manifest files into your current working directory: + ```sh + curl https://raw.githubusercontent.com/newrelic/helm-charts/master/charts/newrelic-logging/k8s/fluent-conf.yml > fluent-conf.yml + curl https://raw.githubusercontent.com/newrelic/helm-charts/master/charts/newrelic-logging/k8s/new-relic-fluent-plugin.yml > new-relic-fluent-plugin.yml + curl https://raw.githubusercontent.com/newrelic/helm-charts/master/charts/newrelic-logging/k8s/rbac.yml > rbac.yml + ``` + + 2. In the downloaded `new-relic-fluent-plugin.yml` file, replace the placeholder value `LICENSE_KEY` with your [New Relic license key](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/license-key). + > For EU users, replace the ENDPOINT environment variable to https://log-api.eu.newrelic.com/log/v1. + + 3. Once the License key has been added, run the following command in your terminal or command-line interface: + ```sh + kubectl apply -f . + ``` + + 4. [OPTIONAL] You can configure how the plugin parses the data by editing the [parsers.conf section in the fluent-conf.yml file](./k8s/fluent-conf.yml#L55-L70). For more information, see Fluent Bit's documentation on [Parsers configuration](https://docs.fluentbit.io/manual/pipeline/parsers). + > By default, tailing is set to `/var/log/containers/*.log`. To change this setting, replace the default path with your preferred path in the [new-relic-fluent-plugin.yml file](./k8s/new-relic-fluent-plugin.yml#L40). + +#### 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 + + 1. Complete the step 1 in [Install the Kubernetes manifests manually](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging#install-the-kubernetes-manifests-manually) + 2. Modify the `new-relic-fluent-plugin.yml` file. Add `HTTP_PROXY` or `HTTPS_PROXY` as environment variables: + ```yaml + ... + containers: + - name: newrelic-logging + env: + - name: ENDPOINT + value : "https://log-api.newrelic.com/log/v1" + - name: HTTP_PROXY + value : "http://http-proxy-hostname:PORT" # We must always specify the protocol (either http:// or https://) + ... + ``` + 3. Continue to the next steps + + ##### Custom proxy + + If you want to set up a custom proxy (eg. using self-signed certificate): + + 1. Complete the step 1 in [Install the Kubernetes manifests manually](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging#install-the-kubernetes-manifests-manually) + 2. Modify the `fluent-conf.yml` and define in the ConfigMap a `caBundle.pem` file with the self-signed certificate: + ```yaml + ... + [OUTPUT] + Name newrelic + Match * + licenseKey ${LICENSE_KEY} + endpoint ${ENDPOINT} + proxy https://https-proxy-hostname:PORT + caBundleFile ${CA_BUNDLE_FILE} + + caBundle.pem: | + -----BEGIN CERTIFICATE----- + MIIB+zCCAWSgAwIBAgIQTiHC/d/NhpHFptZCIoCbNzANBgkrhtiG9w0BAQsFADAS + MBAwDgYDVQQKEwdBY23lIENvMCAXDTcwMDEwMTYwMDBwMFoYDzIwODQwMTI5MTYw + ... + ekFR5glcUVWoFru+EMj4WKmbRATUe3cYQRCThzO2hQ== + -----END CERTIFICATE----- + ... + ``` + 3. Modify `new-relic-fluent-plugin.yml` and define the `CA_BUNDLE_FILE` environment variable pointing to the created ConfigMap file: + ```yaml + ... + containers: + - name: newrelic-logging + env: + - name: ENDPOINT + value : "https://log-api.newrelic.com/log/v1" + - name: CA_BUNDLE_FILE + value: /fluent-bit/etc/caBundle.pem + ... + ``` + 4. Continue to the next steps + +## Configuration + +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]` | +| `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` | +| `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.criEnabled` | We assume that `kubelet`directly communicates with the Docker container engine. Set this to `true` if your K8s installation uses [CRI](https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/) instead, in order to get the logs properly parsed. | `false` | +| `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 "On" to allow excluding pods by adding the annotation `fluentbit.io/exclude: "true"` to pods you wish to exclude. | `Off` | +| `fluentBit.additionalEnvVariables` | Additional environmental variables for fluentbit pods | `[]]` | +| `daemonSet.annotations` | The annotations to add to the `DaemonSet`. | | +| `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.filters` | Contains 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.parsers` | Contains parsers.conf Parsers config | | + + +## Uninstall the Kubernetes plugin + +### Uninstall via Helm (recommended) +Run the following command: +```sh +helm uninstall newrelic-logging +``` + +### Uninstall the Kubernetes manifests manually +Run the following command in the directory where you downloaded the Kubernetes manifests during the installation procedure: +```sh +kubectl delete -f . +``` + +## Resources + +The default set of resources assigned to the pods is shown below: + +```yaml +resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 250m + memory: 64Mi +``` + +## Tolerations + +The default set of tolerations assigned to our daemonset is shown below: + +```yaml +tolerations: + - operator: "Exists" + effect: "NoSchedule" + - operator: "Exists" + effect: "NoExecute" +``` + + +## 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 + +## Troubleshooting + +### I am receiving "Invalid pattern for given tag" +If you are receiving the following error: +```sh +[ warn] [filter_kube] invalid pattern for given tag +``` +In the [new-relic-fluent-plugin.yml file](./k8s/new-relic-fluent-plugin.yml#L40), replace the default code `/var/log/containers/*.log` with the following: +```sh +/var/log/containers/*.{log} +``` diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-enable-windows-values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-enable-windows-values.yaml new file mode 100644 index 000000000..870bc082a --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-enable-windows-values.yaml @@ -0,0 +1,2 @@ +enableLinux: false +enableWindows: true diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-lowdatamode-values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-lowdatamode-values.yaml new file mode 100644 index 000000000..7740338b0 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-lowdatamode-values.yaml @@ -0,0 +1 @@ +lowDataMode: true diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-override-global-lowdatamode.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-override-global-lowdatamode.yaml new file mode 100644 index 000000000..22dd7e05e --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-override-global-lowdatamode.yaml @@ -0,0 +1,3 @@ +global: + lowDataMode: true +lowDataMode: false diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-staging-values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-staging-values.yaml new file mode 100644 index 000000000..efbdccaf8 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-staging-values.yaml @@ -0,0 +1 @@ +nrStaging: true diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-with-empty-global.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-with-empty-global.yaml new file mode 100644 index 000000000..490a0b7ed --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-with-empty-global.yaml @@ -0,0 +1 @@ +global: {} diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-with-empty-values.yaml b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/ci/test-with-empty-values.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/k8s/README.md b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/k8s/README.md new file mode 100644 index 000000000..2da7b34a8 --- /dev/null +++ b/charts/newrelic/nri-bundle/4.3.200/charts/newrelic-logging/k8s/README.md @@ -0,0 +1,63 @@ +# New Relic Logs: Kubernetes manifests +This directory provides plain Kubernetes manifests that can be applied to your cluster to install the Kubernetes Logging plugin. It is provided as an alternative for those users who prefer not using Helm. + +## Installation instructions +* Create a `newrelic` namespace. Run `kubectl create namespace newrelic`. +* Copy all the manifest files in this folder (*.yml files) in your local working directory. +* Configure the plugin. In new-relic-fluent-plugin.yml: + * Specify your New Relic license key in the value for LICENSE_KEY + * Specify your Kubernetes cluster name in the value for CLUSTER_NAME + * If you are in the EU: + * Override the ENDPOINT environment variable to https://log-api.eu.newrelic.com/log/v1 + * Make sure that the license key you are using is an EU key +* From your working directory, run `kubectl apply -f .` on your cluster +* Check [New Relic for your logs](https://docs.newrelic.com/docs/logs/new-relic-logs/get-started/introduction-new-relic-logs#find-data) + +## Find and use your data + +For how to find and query your data in New Relic, see [Find log data](https://docs.newrelic.com/docs/logs/new-relic-logs/get-started/introduction-new-relic-logs#find-data). + +For general querying information, see: +- [Query New Relic data](https://docs.newrelic.com/docs/using-new-relic/data/understand-data/query-new-relic-data) +- [Intro to NRQL](https://docs.newrelic.com/docs/query-data/nrql-new-relic-query-language/getting-started/introduction-nrql) + +## Configuration notes + +We default to tailing `/var/log/containers/*.log`. If you want to change what's tailed, just update the `PATH` +value in `new-relic-fluent-plugin.yml`. + +By default, and to ensure backwards compatibility, we assume that `kubelet` communicates with the `Docker` container engine. With the introduction of the [CRI](https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/), logs placed under `/var/log/containers/*.log` follow a different format, even if they are originally produced in JSON format by the container. If you are using CRI, to be able to parse these logs correctly, you must set `LOG_PARSER` to `"cri"` in `new-relic-fluent-plugin.yml`. + +## Parsing + +We currently support parsing Docker (JSON) and [CRI](https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/) logs. If you want more parsing, feel free to add more parsers in `fluent-conf.yml`. + +Here are some parsers for your parsing pleasure. + +``` +[PARSER] + Name apache + Format regex + Regex ^(?[^ ]*) [^ ]* (?[^ ]*) \[(?