From a24d1ae5259699eb45223ba7d77d3ce25fadf23b Mon Sep 17 00:00:00 2001 From: Nicholas openSUSE Software Engineer Date: Tue, 25 Feb 2025 15:55:15 -0300 Subject: [PATCH] [release-v2.10] 2nd batch release 2.10.3 (#5223) Co-authored-by: rancherbot --- .../rancher-logging-crd-105.2.1+up4.10.0.tgz | Bin 0 -> 175027 bytes .../rancher-logging-105.2.1+up4.10.0.tgz | Bin 0 -> 20075 bytes ...ancher-monitoring-crd-105.1.3+up61.3.2.tgz | Bin 0 -> 331943 bytes .../rancher-monitoring-105.1.3+up61.3.2.tgz | Bin 0 -> 487891 bytes .../105.2.1+up4.10.0/Chart.yaml | 10 + .../105.2.1+up4.10.0/README.md | 2 + ...xtensions.banzaicloud.io_eventtailers.yaml | 2496 ++ ...extensions.banzaicloud.io_hosttailers.yaml | 2686 ++ .../logging.banzaicloud.io_clusterflows.yaml | 2166 ++ ...logging.banzaicloud.io_clusteroutputs.yaml | 14824 +++++++++++ .../logging.banzaicloud.io_flows.yaml | 2150 ++ ...ogging.banzaicloud.io_fluentbitagents.yaml | 2633 ++ ...logging.banzaicloud.io_fluentdconfigs.yaml | 3345 +++ .../logging.banzaicloud.io_loggingroutes.yaml | 106 + .../logging.banzaicloud.io_loggings.yaml | 21063 ++++++++++++++++ .../logging.banzaicloud.io_nodeagents.yaml | 4867 ++++ .../logging.banzaicloud.io_outputs.yaml | 14090 +++++++++++ ...g.banzaicloud.io_syslogngclusterflows.yaml | 360 + ...banzaicloud.io_syslogngclusteroutputs.yaml | 3356 +++ ...ogging.banzaicloud.io_syslogngconfigs.yaml | 8282 ++++++ .../logging.banzaicloud.io_syslogngflows.yaml | 364 + ...ogging.banzaicloud.io_syslogngoutputs.yaml | 3350 +++ .../105.2.1+up4.10.0/.helmignore | 26 + .../105.2.1+up4.10.0/Chart.yaml | 30 + .../105.2.1+up4.10.0/README.md | 135 + .../105.2.1+up4.10.0/app-readme.md | 45 + .../105.2.1+up4.10.0/templates/NOTES.txt | 0 .../templates/_generic_fluentbitagent.yaml | 85 + .../templates/_generic_logging.yaml | 75 + .../105.2.1+up4.10.0/templates/_helpers.tpl | 231 + .../templates/clusterrole.yaml | 242 + .../templates/clusterrolebinding.yaml | 18 + .../105.2.1+up4.10.0/templates/crds.yaml | 6 + .../templates/deployment.yaml | 79 + .../templates/extra-manifests.yaml | 4 + .../templates/logging/clusterflows.yaml | 14 + .../templates/logging/clusteroutputs.yaml | 14 + .../templates/logging/eventtailer.yaml | 41 + .../templates/logging/fluentbit.yaml | 17 + .../templates/logging/hosttailer.yaml | 31 + .../templates/logging/logging.yaml | 63 + .../loggings/aks/fluentbitagent.yaml | 20 + .../templates/loggings/aks/logging.yaml | 12 + .../loggings/eks/fluentbitagent.yaml | 21 + .../templates/loggings/eks/logging.yaml | 20 + .../loggings/gke/fluentbitagent.yaml | 20 + .../templates/loggings/gke/logging.yaml | 12 + .../templates/loggings/k3s/configmap.yaml | 57 + .../templates/loggings/k3s/daemonset.yaml | 112 + .../loggings/k3s/fluentbitagent.yaml | 21 + .../loggings/k3s/logging-k3s-openrc.yaml | 12 + .../loggings/kube-audit/fluentbitagent.yaml | 24 + .../loggings/kube-audit/logging.yaml | 15 + .../templates/loggings/rke/configmap.yaml | 29 + .../templates/loggings/rke/daemonset.yaml | 124 + .../templates/loggings/rke2/configmap.yaml | 69 + .../templates/loggings/rke2/daemonset.yaml | 118 + .../loggings/root/fluentbitagent.yaml | 29 + .../templates/loggings/root/logging.yaml | 67 + .../105.2.1+up4.10.0/templates/service.yaml | 20 + .../templates/service_monitor.yaml | 30 + .../templates/serviceaccount.yaml | 14 + .../templates/test_receiver.yaml | 53 + .../105.2.1+up4.10.0/templates/userrole.yaml | 39 + .../105.2.1+up4.10.0/templates/userroles.yaml | 35 + .../templates/validate-install-crd.yaml | 29 + .../templates/validate-install.yaml | 5 + .../templates/validate-psp-install.yaml | 7 + .../values-logging-example.yaml | 24 + .../105.2.1+up4.10.0/values.yaml | 495 + .../105.1.3+up61.3.2/Chart.yaml | 10 + .../105.1.3+up61.3.2/README.md | 24 + .../105.1.3+up61.3.2/files/crd-manifest.tgz | Bin 0 -> 331364 bytes .../105.1.3+up61.3.2/templates/_helpers.tpl | 30 + .../105.1.3+up61.3.2/templates/jobs.yaml | 102 + .../105.1.3+up61.3.2/templates/manifest.yaml | 8 + .../105.1.3+up61.3.2/templates/rbac.yaml | 76 + .../templates/validate-psp-install.yaml | 7 + .../105.1.3+up61.3.2/values.yaml | 17 + .../105.1.3+up61.3.2/.editorconfig | 5 + .../105.1.3+up61.3.2/.helmignore | 29 + .../105.1.3+up61.3.2/CHANGELOG.md | 47 + .../105.1.3+up61.3.2/CONTRIBUTING.md | 12 + .../105.1.3+up61.3.2/Chart.yaml | 126 + .../105.1.3+up61.3.2/README.md | 1140 + .../105.1.3+up61.3.2/app-README.md | 46 + .../charts/grafana/.helmignore | 23 + .../charts/grafana/Chart.yaml | 41 + .../105.1.3+up61.3.2/charts/grafana/README.md | 778 + .../grafana/dashboards/custom-dashboard.json | 1 + .../charts/grafana/templates/NOTES.txt | 55 + .../charts/grafana/templates/_config.tpl | 172 + .../charts/grafana/templates/_helpers.tpl | 305 + .../charts/grafana/templates/_pod.tpl | 1306 + .../charts/grafana/templates/clusterrole.yaml | 25 + .../grafana/templates/clusterrolebinding.yaml | 24 + .../grafana/templates/configSecret.yaml | 43 + .../configmap-dashboard-provider.yaml | 15 + .../charts/grafana/templates/configmap.yaml | 20 + .../templates/dashboards-json-configmap.yaml | 38 + .../charts/grafana/templates/deployment.yaml | 53 + .../grafana/templates/extra-manifests.yaml | 4 + .../grafana/templates/headless-service.yaml | 22 + .../charts/grafana/templates/hpa.yaml | 52 + .../templates/image-renderer-deployment.yaml | 199 + .../grafana/templates/image-renderer-hpa.yaml | 47 + .../image-renderer-network-policy.yaml | 79 + .../templates/image-renderer-service.yaml | 31 + .../image-renderer-servicemonitor.yaml | 48 + .../charts/grafana/templates/ingress.yaml | 78 + .../grafana/templates/networkpolicy.yaml | 61 + .../grafana/templates/nginx-config.yaml | 94 + .../templates/poddisruptionbudget.yaml | 22 + .../grafana/templates/podsecuritypolicy.yaml | 45 + .../charts/grafana/templates/pvc.yaml | 41 + .../charts/grafana/templates/role.yaml | 32 + .../charts/grafana/templates/rolebinding.yaml | 25 + .../charts/grafana/templates/secret-env.yaml | 14 + .../charts/grafana/templates/secret.yaml | 16 + .../charts/grafana/templates/service.yaml | 67 + .../grafana/templates/serviceaccount.yaml | 17 + .../grafana/templates/servicemonitor.yaml | 66 + .../charts/grafana/templates/statefulset.yaml | 58 + .../templates/tests/test-configmap.yaml | 20 + .../tests/test-podsecuritypolicy.yaml | 32 + .../grafana/templates/tests/test-role.yaml | 17 + .../templates/tests/test-rolebinding.yaml | 20 + .../templates/tests/test-serviceaccount.yaml | 12 + .../charts/grafana/templates/tests/test.yaml | 53 + .../charts/grafana/values.yaml | 1365 + .../charts/hardenedKubelet/.helmignore | 23 + .../charts/hardenedKubelet/Chart.yaml | 15 + .../charts/hardenedKubelet/README.md | 90 + .../hardenedKubelet/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/hardenedKubelet/values.yaml | 166 + .../charts/hardenedNodeExporter/.helmignore | 23 + .../charts/hardenedNodeExporter/Chart.yaml | 15 + .../charts/hardenedNodeExporter/README.md | 90 + .../templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/hardenedNodeExporter/values.yaml | 166 + .../charts/k3sServer/.helmignore | 23 + .../charts/k3sServer/Chart.yaml | 15 + .../charts/k3sServer/README.md | 90 + .../charts/k3sServer/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../k3sServer/templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../k3sServer/templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/k3sServer/values.yaml | 166 + .../charts/kube-state-metrics/.helmignore | 21 + .../charts/kube-state-metrics/Chart.yaml | 32 + .../charts/kube-state-metrics/README.md | 85 + .../kube-state-metrics/templates/NOTES.txt | 23 + .../kube-state-metrics/templates/_helpers.tpl | 196 + .../templates/ciliumnetworkpolicy.yaml | 33 + .../templates/clusterrolebinding.yaml | 20 + .../templates/crs-configmap.yaml | 16 + .../templates/deployment.yaml | 313 + .../templates/extra-manifests.yaml | 4 + .../templates/kubeconfig-secret.yaml | 12 + .../templates/networkpolicy.yaml | 43 + .../kube-state-metrics/templates/pdb.yaml | 18 + .../templates/podsecuritypolicy.yaml | 39 + .../templates/psp-clusterrole.yaml | 19 + .../templates/psp-clusterrolebinding.yaml | 16 + .../templates/rbac-configmap.yaml | 22 + .../kube-state-metrics/templates/role.yaml | 215 + .../templates/rolebinding.yaml | 24 + .../kube-state-metrics/templates/service.yaml | 53 + .../templates/serviceaccount.yaml | 18 + .../templates/servicemonitor.yaml | 126 + .../templates/stsdiscovery-role.yaml | 26 + .../templates/stsdiscovery-rolebinding.yaml | 17 + .../templates/verticalpodautoscaler.yaml | 44 + .../charts/kube-state-metrics/values.yaml | 523 + .../kubeAdmControllerManager/.helmignore | 23 + .../kubeAdmControllerManager/Chart.yaml | 15 + .../charts/kubeAdmControllerManager/README.md | 90 + .../templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../kubeAdmControllerManager/values.yaml | 166 + .../charts/kubeAdmEtcd/.helmignore | 23 + .../charts/kubeAdmEtcd/Chart.yaml | 15 + .../charts/kubeAdmEtcd/README.md | 90 + .../charts/kubeAdmEtcd/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../kubeAdmEtcd/templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/kubeAdmEtcd/values.yaml | 166 + .../charts/kubeAdmProxy/.helmignore | 23 + .../charts/kubeAdmProxy/Chart.yaml | 15 + .../charts/kubeAdmProxy/README.md | 90 + .../kubeAdmProxy/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/kubeAdmProxy/values.yaml | 166 + .../charts/kubeAdmScheduler/.helmignore | 23 + .../charts/kubeAdmScheduler/Chart.yaml | 15 + .../charts/kubeAdmScheduler/README.md | 90 + .../kubeAdmScheduler/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/kubeAdmScheduler/values.yaml | 166 + .../charts/prometheus-adapter/.helmignore | 21 + .../charts/prometheus-adapter/Chart.yaml | 27 + .../charts/prometheus-adapter/README.md | 160 + .../prometheus-adapter/templates/NOTES.txt | 9 + .../prometheus-adapter/templates/_helpers.tpl | 113 + .../templates/certmanager.yaml | 76 + .../cluster-role-binding-auth-delegator.yaml | 20 + .../cluster-role-binding-auth-reader.yaml | 20 + .../cluster-role-binding-resource-reader.yaml | 20 + .../cluster-role-resource-reader.yaml | 24 + .../templates/configmap.yaml | 97 + .../templates/custom-metrics-apiservice.yaml | 34 + ...stom-metrics-cluster-role-binding-hpa.yaml | 24 + .../custom-metrics-cluster-role.yaml | 17 + .../templates/deployment.yaml | 151 + .../external-metrics-apiservice.yaml | 34 + ...rnal-metrics-cluster-role-binding-hpa.yaml | 20 + .../external-metrics-cluster-role.yaml | 20 + .../prometheus-adapter/templates/pdb.yaml | 23 + .../prometheus-adapter/templates/psp.yaml | 66 + .../resource-metrics-apiservice.yaml | 34 + ...resource-metrics-cluster-role-binding.yaml | 20 + .../resource-metrics-cluster-role.yaml | 23 + .../templates/role-binding-auth-reader.yaml | 21 + .../prometheus-adapter/templates/secret.yaml | 17 + .../prometheus-adapter/templates/service.yaml | 32 + .../templates/serviceaccount.yaml | 18 + .../charts/prometheus-adapter/values.yaml | 292 + .../prometheus-node-exporter/.helmignore | 21 + .../prometheus-node-exporter/Chart.yaml | 25 + .../charts/prometheus-node-exporter/README.md | 96 + .../templates/NOTES.txt | 29 + .../templates/_helpers.tpl | 236 + .../templates/clusterrole.yaml | 19 + .../templates/clusterrolebinding.yaml | 20 + .../templates/daemonset.yaml | 312 + .../templates/endpoints.yaml | 18 + .../templates/extra-manifests.yaml | 4 + .../templates/networkpolicy.yaml | 23 + .../templates/podmonitor.yaml | 91 + .../templates/psp-clusterrole.yaml | 14 + .../templates/psp-clusterrolebinding.yaml | 16 + .../templates/psp.yaml | 49 + .../templates/rbac-configmap.yaml | 16 + .../templates/service.yaml | 35 + .../templates/serviceaccount.yaml | 18 + .../templates/servicemonitor.yaml | 71 + .../templates/verticalpodautoscaler.yaml | 40 + .../prometheus-node-exporter/values.yaml | 539 + .../charts/rke2ControllerManager/.helmignore | 23 + .../charts/rke2ControllerManager/Chart.yaml | 15 + .../charts/rke2ControllerManager/README.md | 90 + .../templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rke2ControllerManager/values.yaml | 166 + .../charts/rke2Etcd/.helmignore | 23 + .../charts/rke2Etcd/Chart.yaml | 15 + .../charts/rke2Etcd/README.md | 90 + .../charts/rke2Etcd/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../rke2Etcd/templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../rke2Etcd/templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rke2Etcd/values.yaml | 166 + .../charts/rke2IngressNginx/.helmignore | 23 + .../charts/rke2IngressNginx/Chart.yaml | 15 + .../charts/rke2IngressNginx/README.md | 90 + .../rke2IngressNginx/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rke2IngressNginx/values.yaml | 166 + .../charts/rke2Proxy/.helmignore | 23 + .../charts/rke2Proxy/Chart.yaml | 15 + .../charts/rke2Proxy/README.md | 90 + .../charts/rke2Proxy/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../rke2Proxy/templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../rke2Proxy/templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rke2Proxy/values.yaml | 166 + .../charts/rke2Scheduler/.helmignore | 23 + .../charts/rke2Scheduler/Chart.yaml | 15 + .../charts/rke2Scheduler/README.md | 90 + .../rke2Scheduler/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rke2Scheduler/values.yaml | 166 + .../charts/rkeControllerManager/.helmignore | 23 + .../charts/rkeControllerManager/Chart.yaml | 15 + .../charts/rkeControllerManager/README.md | 90 + .../templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rkeControllerManager/values.yaml | 166 + .../charts/rkeEtcd/.helmignore | 23 + .../charts/rkeEtcd/Chart.yaml | 15 + .../105.1.3+up61.3.2/charts/rkeEtcd/README.md | 90 + .../charts/rkeEtcd/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../rkeEtcd/templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../rkeEtcd/templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rkeEtcd/values.yaml | 166 + .../charts/rkeIngressNginx/.helmignore | 23 + .../charts/rkeIngressNginx/Chart.yaml | 15 + .../charts/rkeIngressNginx/README.md | 90 + .../rkeIngressNginx/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rkeIngressNginx/values.yaml | 166 + .../charts/rkeProxy/.helmignore | 23 + .../charts/rkeProxy/Chart.yaml | 15 + .../charts/rkeProxy/README.md | 90 + .../charts/rkeProxy/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../rkeProxy/templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../rkeProxy/templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rkeProxy/values.yaml | 166 + .../charts/rkeScheduler/.helmignore | 23 + .../charts/rkeScheduler/Chart.yaml | 15 + .../charts/rkeScheduler/README.md | 90 + .../rkeScheduler/templates/_helpers.tpl | 170 + .../templates/pushprox-clients-rbac.yaml | 97 + .../templates/pushprox-clients.yaml | 157 + .../templates/pushprox-proxy-rbac.yaml | 68 + .../templates/pushprox-proxy.yaml | 57 + .../templates/pushprox-servicemonitor.yaml | 45 + .../templates/validate-install-crd.yaml | 14 + .../templates/validate-psp-install.yaml | 7 + .../charts/rkeScheduler/values.yaml | 166 + .../charts/windowsExporter/.helmignore | 21 + .../charts/windowsExporter/Chart.yaml | 24 + .../charts/windowsExporter/README.md | 42 + .../scripts/configure-firewall.ps1 | 31 + .../windowsExporter/templates/_helpers.tpl | 216 + .../windowsExporter/templates/config.yaml | 14 + .../windowsExporter/templates/daemonset.yaml | 200 + .../windowsExporter/templates/podmonitor.yaml | 91 + .../templates/scriptConfig.yaml | 14 + .../windowsExporter/templates/service.yaml | 32 + .../templates/serviceaccount.yaml | 17 + .../templates/servicemonitor.yaml | 75 + .../charts/windowsExporter/values.yaml | 367 + .../files/ingress-nginx/nginx.json | 1445 ++ .../request-handling-performance.json | 963 + .../cluster/rancher-cluster-nodes.json | 793 + .../rancher/cluster/rancher-cluster.json | 776 + .../files/rancher/fleet/bundle.json | 246 + .../files/rancher/fleet/bundledeployment.json | 219 + .../files/rancher/fleet/cluster.json | 484 + .../files/rancher/fleet/clustergroup.json | 468 + .../rancher/fleet/controller-runtime.json | 454 + .../files/rancher/fleet/gitrepo.json | 325 + .../rancher/home/rancher-default-home.json | 1290 + .../files/rancher/k8s/rancher-etcd-nodes.json | 687 + .../files/rancher/k8s/rancher-etcd.json | 669 + .../k8s/rancher-k8s-components-nodes.json | 527 + .../rancher/k8s/rancher-k8s-components.json | 519 + .../files/rancher/logging/fluentbit.json | 760 + .../files/rancher/logging/fluentd.json | 3221 +++ .../rancher/nodes/rancher-node-detail.json | 805 + .../files/rancher/nodes/rancher-node.json | 792 + .../performance/performance-debugging.json | 1652 ++ .../rancher/pods/rancher-pod-containers.json | 636 + .../files/rancher/pods/rancher-pod.json | 636 + .../workloads/rancher-workload-pods.json | 652 + .../rancher/workloads/rancher-workload.json | 652 + .../delete-workloads-with-old-labels.sh | 14 + .../105.1.3+up61.3.2/templates/NOTES.txt | 4 + .../105.1.3+up61.3.2/templates/_helpers.tpl | 472 + .../templates/alertmanager/alertmanager.yaml | 195 + .../templates/alertmanager/extrasecret.yaml | 20 + .../templates/alertmanager/ingress.yaml | 78 + .../alertmanager/ingressperreplica.yaml | 67 + .../alertmanager/podDisruptionBudget.yaml | 21 + .../templates/alertmanager/psp-role.yaml | 23 + .../alertmanager/psp-rolebinding.yaml | 20 + .../templates/alertmanager/psp.yaml | 47 + .../templates/alertmanager/secret.yaml | 37 + .../templates/alertmanager/service.yaml | 72 + .../alertmanager/serviceaccount.yaml | 21 + .../alertmanager/servicemonitor.yaml | 84 + .../alertmanager/serviceperreplica.yaml | 49 + .../templates/exporters/core-dns/service.yaml | 28 + .../exporters/core-dns/servicemonitor.yaml | 58 + .../kube-api-server/servicemonitor.yaml | 57 + .../kube-controller-manager/endpoints.yaml | 22 + .../kube-controller-manager/service.yaml | 33 + .../servicemonitor.yaml | 69 + .../templates/exporters/kube-dns/service.yaml | 32 + .../exporters/kube-dns/servicemonitor.yaml | 71 + .../exporters/kube-etcd/endpoints.yaml | 20 + .../exporters/kube-etcd/service.yaml | 31 + .../exporters/kube-etcd/servicemonitor.yaml | 75 + .../exporters/kube-proxy/endpoints.yaml | 20 + .../exporters/kube-proxy/service.yaml | 31 + .../exporters/kube-proxy/servicemonitor.yaml | 63 + .../exporters/kube-scheduler/endpoints.yaml | 22 + .../exporters/kube-scheduler/service.yaml | 33 + .../kube-scheduler/servicemonitor.yaml | 69 + .../kube-state-metrics/validate.yaml | 7 + .../exporters/kubelet/servicemonitor.yaml | 246 + .../exporters/node-exporter/validate.yaml | 3 + .../templates/extra-objects.yaml | 4 + .../grafana/configmap-dashboards.yaml | 24 + .../grafana/configmaps-datasources.yaml | 81 + .../alertmanager-overview.yaml | 616 + .../grafana/dashboards-1.14/apiserver.yaml | 1772 ++ .../dashboards-1.14/cluster-total.yaml | 1882 ++ .../dashboards-1.14/controller-manager.yaml | 1196 + .../grafana/dashboards-1.14/etcd.yaml | 1229 + .../dashboards-1.14/grafana-overview.yaml | 635 + .../grafana/dashboards-1.14/k8s-coredns.yaml | 1534 ++ .../k8s-resources-cluster.yaml | 3088 +++ .../k8s-resources-multicluster.yaml | 24 + .../k8s-resources-namespace.yaml | 2797 ++ .../dashboards-1.14/k8s-resources-node.yaml | 1026 + .../dashboards-1.14/k8s-resources-pod.yaml | 2469 ++ .../k8s-resources-windows-cluster.yaml | 24 + .../k8s-resources-windows-namespace.yaml | 24 + .../k8s-resources-windows-pod.yaml | 24 + .../k8s-resources-workload.yaml | 2024 ++ .../k8s-resources-workloads-namespace.yaml | 2189 ++ .../k8s-windows-cluster-rsrc-use.yaml | 24 + .../k8s-windows-node-rsrc-use.yaml | 24 + .../grafana/dashboards-1.14/kubelet.yaml | 2256 ++ .../dashboards-1.14/namespace-by-pod.yaml | 1464 ++ .../namespace-by-workload.yaml | 1736 ++ .../node-cluster-rsrc-use.yaml | 1063 + .../dashboards-1.14/node-rsrc-use.yaml | 1089 + .../grafana/dashboards-1.14/nodes-darwin.yaml | 1073 + .../grafana/dashboards-1.14/nodes.yaml | 1066 + .../persistentvolumesusage.yaml | 587 + .../grafana/dashboards-1.14/pod-total.yaml | 1228 + .../prometheus-remote-write.yaml | 1674 ++ .../grafana/dashboards-1.14/prometheus.yaml | 1235 + .../grafana/dashboards-1.14/proxy.yaml | 1276 + .../grafana/dashboards-1.14/scheduler.yaml | 1118 + .../dashboards-1.14/workload-total.yaml | 1438 ++ .../templates/grafana/namespaces.yaml | 13 + .../_prometheus-operator.tpl | 7 + .../_prometheus-operator-webhook.tpl | 6 + .../deployment/deployment.yaml | 143 + .../admission-webhooks/deployment/pdb.yaml | 15 + .../deployment/service.yaml | 62 + .../deployment/serviceaccount.yaml | 15 + .../ciliumnetworkpolicy-createSecret.yaml | 36 + .../ciliumnetworkpolicy-patchWebhook.yaml | 36 + .../job-patch/clusterrole.yaml | 33 + .../job-patch/clusterrolebinding.yaml | 20 + .../job-patch/job-createSecret.yaml | 73 + .../job-patch/job-patchWebhook.yaml | 74 + .../job-patch/networkpolicy-createSecret.yaml | 33 + .../job-patch/networkpolicy-patchWebhook.yaml | 33 + .../admission-webhooks/job-patch/psp.yaml | 47 + .../admission-webhooks/job-patch/role.yaml | 21 + .../job-patch/rolebinding.yaml | 21 + .../job-patch/serviceaccount.yaml | 18 + .../mutatingWebhookConfiguration.yaml | 81 + .../validatingWebhookConfiguration.yaml | 81 + .../aggregate-clusterroles.yaml | 29 + .../prometheus-operator/certmanager.yaml | 55 + .../ciliumnetworkpolicy.yaml | 40 + .../prometheus-operator/clusterrole.yaml | 109 + .../clusterrolebinding.yaml | 16 + .../prometheus-operator/deployment.yaml | 207 + .../prometheus-operator/networkpolicy.yaml | 29 + .../prometheus-operator/psp-clusterrole.yaml | 21 + .../psp-clusterrolebinding.yaml | 18 + .../templates/prometheus-operator/psp.yaml | 46 + .../prometheus-operator/service.yaml | 61 + .../prometheus-operator/serviceaccount.yaml | 14 + .../prometheus-operator/servicemonitor.yaml | 57 + .../verticalpodautoscaler.yaml | 40 + .../templates/prometheus/_rules.tpl | 44 + .../additionalAlertRelabelConfigs.yaml | 16 + .../additionalAlertmanagerConfigs.yaml | 16 + .../prometheus/additionalPrometheusRules.yaml | 43 + .../prometheus/additionalScrapeConfigs.yaml | 20 + .../prometheus/ciliumnetworkpolicy.yaml | 27 + .../templates/prometheus/clusterrole.yaml | 43 + .../prometheus/clusterrolebinding.yaml | 18 + .../templates/prometheus/csi-secret.yaml | 12 + .../templates/prometheus/extrasecret.yaml | 20 + .../templates/prometheus/ingress.yaml | 77 + .../prometheus/ingressThanosSidecar.yaml | 77 + .../prometheus/ingressperreplica.yaml | 67 + .../templates/prometheus/networkpolicy.yaml | 34 + .../templates/prometheus/nginx-config.yaml | 68 + .../prometheus/podDisruptionBudget.yaml | 25 + .../templates/prometheus/podmonitors.yaml | 38 + .../templates/prometheus/prometheus.yaml | 481 + .../templates/prometheus/psp-clusterrole.yaml | 22 + .../prometheus/psp-clusterrolebinding.yaml | 19 + .../templates/prometheus/psp.yaml | 58 + .../rules-1.14/alertmanager.rules.yaml | 305 + .../rules-1.14/config-reloaders.yaml | 57 + .../templates/prometheus/rules-1.14/etcd.yaml | 461 + .../prometheus/rules-1.14/general.rules.yaml | 125 + ...les.container_cpu_usage_seconds_total.yaml | 43 + .../k8s.rules.container_memory_cache.yaml | 42 + .../k8s.rules.container_memory_rss.yaml | 42 + .../k8s.rules.container_memory_swap.yaml | 42 + ...es.container_memory_working_set_bytes.yaml | 42 + .../k8s.rules.container_resource.yaml | 168 + .../rules-1.14/k8s.rules.pod_owner.yaml | 107 + .../prometheus/rules-1.14/k8s.rules.yaml | 237 + .../kube-apiserver-availability.rules.yaml | 273 + .../kube-apiserver-burnrate.rules.yaml | 440 + .../kube-apiserver-histogram.rules.yaml | 53 + .../rules-1.14/kube-apiserver-slos.yaml | 159 + .../kube-prometheus-general.rules.yaml | 49 + .../kube-prometheus-node-recording.rules.yaml | 93 + .../rules-1.14/kube-scheduler.rules.yaml | 135 + .../rules-1.14/kube-state-metrics.yaml | 152 + .../prometheus/rules-1.14/kubelet.rules.yaml | 65 + .../rules-1.14/kubernetes-apps.yaml | 568 + .../rules-1.14/kubernetes-resources.yaml | 282 + .../rules-1.14/kubernetes-storage.yaml | 216 + .../kubernetes-system-apiserver.yaml | 193 + .../kubernetes-system-controller-manager.yaml | 57 + .../kubernetes-system-kube-proxy.yaml | 52 + .../rules-1.14/kubernetes-system-kubelet.yaml | 379 + .../kubernetes-system-scheduler.yaml | 54 + .../rules-1.14/kubernetes-system.yaml | 87 + .../rules-1.14/node-exporter.rules.yaml | 188 + .../prometheus/rules-1.14/node-exporter.yaml | 801 + .../prometheus/rules-1.14/node-network.yaml | 55 + .../prometheus/rules-1.14/node.rules.yaml | 109 + .../rules-1.14/prometheus-operator.yaml | 253 + .../prometheus/rules-1.14/prometheus.yaml | 735 + .../rules-1.14/windows.node.rules.yaml | 301 + .../rules-1.14/windows.pod.rules.yaml | 158 + .../templates/prometheus/secret.yaml | 15 + .../templates/prometheus/service.yaml | 84 + .../prometheus/serviceThanosSidecar.yaml | 43 + .../serviceThanosSidecarExternal.yaml | 46 + .../templates/prometheus/serviceaccount.yaml | 21 + .../templates/prometheus/servicemonitor.yaml | 97 + .../servicemonitorThanosSidecar.yaml | 55 + .../templates/prometheus/servicemonitors.yaml | 47 + .../prometheus/serviceperreplica.yaml | 58 + .../rancher-monitoring/clusterrole.yaml | 135 + .../rancher-monitoring/config-role.yaml | 48 + .../rancher-monitoring/dashboard-role.yaml | 47 + .../addons/ingress-nginx-dashboard.yaml | 18 + .../rancher/cluster-dashboards.yaml | 17 + .../dashboards/rancher/default-dashboard.yaml | 17 + .../dashboards/rancher/fleet-dashboards.yaml | 17 + .../rancher/fluentbit-dashboard.yaml | 17 + .../dashboards/rancher/fluentd-dashboard.yaml | 17 + .../dashboards/rancher/k8s-dashboards.yaml | 31 + .../dashboards/rancher/nodes-dashboards.yaml | 17 + .../rancher/performance-dashboards.yaml | 18 + .../dashboards/rancher/pods-dashboards.yaml | 17 + .../rancher/workload-dashboards.yaml | 17 + .../exporters/fleet/servicemonitor.yaml | 53 + .../ingress-nginx/network-policy.yaml | 19 + .../exporters/ingress-nginx/service.yaml | 27 + .../ingress-nginx/servicemonitor.yaml | 49 + .../exporters/rancher/servicemonitor.yaml | 58 + .../rancher-monitoring/hardened.yaml | 91 + .../rancher-monitoring/upgrade/configmap.yaml | 13 + .../rancher-monitoring/upgrade/job.yaml | 46 + .../rancher-monitoring/upgrade/rbac.yaml | 86 + .../templates/thanos-ruler/extrasecret.yaml | 20 + .../templates/thanos-ruler/ingress.yaml | 77 + .../thanos-ruler/podDisruptionBudget.yaml | 21 + .../templates/thanos-ruler/ruler.yaml | 200 + .../templates/thanos-ruler/secret.yaml | 26 + .../templates/thanos-ruler/service.yaml | 57 + .../thanos-ruler/serviceaccount.yaml | 20 + .../thanos-ruler/servicemonitor.yaml | 82 + .../templates/validate-install-crd.yaml | 23 + .../templates/validate-psp-install.yaml | 2 + .../105.1.3+up61.3.2/values.yaml | 5567 ++++ index.yaml | 192 + regsync.yaml | 12 +- release.yaml | 22 +- 658 files changed, 198687 insertions(+), 20 deletions(-) create mode 100644 assets/rancher-logging-crd/rancher-logging-crd-105.2.1+up4.10.0.tgz create mode 100644 assets/rancher-logging/rancher-logging-105.2.1+up4.10.0.tgz create mode 100644 assets/rancher-monitoring-crd/rancher-monitoring-crd-105.1.3+up61.3.2.tgz create mode 100644 assets/rancher-monitoring/rancher-monitoring-105.1.3+up61.3.2.tgz create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/Chart.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/README.md create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging-extensions.banzaicloud.io_eventtailers.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging-extensions.banzaicloud.io_hosttailers.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_clusterflows.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_clusteroutputs.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_flows.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_fluentbitagents.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_fluentdconfigs.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_loggingroutes.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_loggings.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_nodeagents.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_outputs.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_syslogngclusterflows.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_syslogngclusteroutputs.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_syslogngconfigs.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_syslogngflows.yaml create mode 100644 charts/rancher-logging-crd/105.2.1+up4.10.0/templates/logging.banzaicloud.io_syslogngoutputs.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/.helmignore create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/Chart.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/README.md create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/app-readme.md create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/NOTES.txt create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/_generic_fluentbitagent.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/_generic_logging.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/_helpers.tpl create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/clusterrole.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/clusterrolebinding.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/crds.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/deployment.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/extra-manifests.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/logging/clusterflows.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/logging/clusteroutputs.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/logging/eventtailer.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/logging/fluentbit.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/logging/hosttailer.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/logging/logging.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/aks/fluentbitagent.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/aks/logging.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/eks/fluentbitagent.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/eks/logging.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/gke/fluentbitagent.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/gke/logging.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/configmap.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/daemonset.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/fluentbitagent.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/logging-k3s-openrc.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/kube-audit/fluentbitagent.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/kube-audit/logging.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke/configmap.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke/daemonset.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke2/configmap.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke2/daemonset.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/root/fluentbitagent.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/root/logging.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/service.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/service_monitor.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/serviceaccount.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/test_receiver.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/userrole.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/userroles.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/validate-install-crd.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/validate-install.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/templates/validate-psp-install.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/values-logging-example.yaml create mode 100644 charts/rancher-logging/105.2.1+up4.10.0/values.yaml create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/Chart.yaml create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/README.md create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/files/crd-manifest.tgz create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/jobs.yaml create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/manifest.yaml create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/rbac.yaml create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring-crd/105.1.3+up61.3.2/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/.editorconfig create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/CHANGELOG.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/CONTRIBUTING.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/app-README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/dashboards/custom-dashboard.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/NOTES.txt create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_config.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_pod.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configSecret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configmap-dashboard-provider.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configmap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/dashboards-json-configmap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/deployment.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/extra-manifests.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/headless-service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/hpa.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-deployment.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-hpa.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-network-policy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/ingress.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/networkpolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/nginx-config.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/poddisruptionbudget.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/podsecuritypolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/pvc.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/rolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/secret-env.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/secret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/statefulset.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-configmap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-podsecuritypolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-rolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/NOTES.txt create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/crs-configmap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/deployment.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/extra-manifests.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/kubeconfig-secret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/networkpolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/pdb.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/podsecuritypolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/psp-clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/rbac-configmap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/rolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/stsdiscovery-role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/NOTES.txt create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/certmanager.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-auth-delegator.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-auth-reader.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-resource-reader.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-resource-reader.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/configmap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-apiservice.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-cluster-role-binding-hpa.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-cluster-role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/deployment.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-apiservice.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-cluster-role-binding-hpa.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-cluster-role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/pdb.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/psp.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-apiservice.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-cluster-role-binding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-cluster-role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/role-binding-auth-reader.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/secret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/NOTES.txt create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/daemonset.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/endpoints.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/extra-manifests.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/networkpolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/podmonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp-clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp-clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/rbac-configmap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/verticalpodautoscaler.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-clients-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-clients.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-proxy-rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/.helmignore create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/Chart.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/README.md create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/scripts/configure-firewall.ps1 create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/config.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/daemonset.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/podmonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/scriptConfig.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/values.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/ingress-nginx/nginx.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/ingress-nginx/request-handling-performance.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/cluster/rancher-cluster-nodes.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/cluster/rancher-cluster.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/bundle.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/bundledeployment.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/cluster.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/clustergroup.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/controller-runtime.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/gitrepo.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/home/rancher-default-home.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-etcd-nodes.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-etcd.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-k8s-components-nodes.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-k8s-components.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/logging/fluentbit.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/logging/fluentd.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/nodes/rancher-node-detail.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/nodes/rancher-node.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/performance/performance-debugging.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/pods/rancher-pod-containers.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/pods/rancher-pod.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/workloads/rancher-workload-pods.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/workloads/rancher-workload.json create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/files/upgrade/scripts/delete-workloads-with-old-labels.sh create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/NOTES.txt create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/_helpers.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/alertmanager.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/extrasecret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/ingress.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/ingressperreplica.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/podDisruptionBudget.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp-role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp-rolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/secret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/serviceperreplica.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/core-dns/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/core-dns/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-api-server/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/endpoints.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-dns/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-dns/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/endpoints.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/endpoints.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/endpoints.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-state-metrics/validate.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kubelet/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/node-exporter/validate.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/extra-objects.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/configmap-dashboards.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/configmaps-datasources.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/alertmanager-overview.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/apiserver.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/cluster-total.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/controller-manager.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/etcd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/grafana-overview.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-coredns.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-cluster.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-multicluster.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-namespace.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-node.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-pod.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-cluster.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-namespace.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-pod.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-workload.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-workloads-namespace.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-windows-cluster-rsrc-use.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-windows-node-rsrc-use.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/kubelet.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/namespace-by-pod.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/namespace-by-workload.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/node-cluster-rsrc-use.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/node-rsrc-use.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/nodes-darwin.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/nodes.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/persistentvolumesusage.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/pod-total.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/prometheus-remote-write.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/prometheus.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/scheduler.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/workload-total.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/namespaces.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/_prometheus-operator.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/_prometheus-operator-webhook.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/deployment.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/pdb.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-createSecret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-patchWebhook.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/job-createSecret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/job-patchWebhook.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-createSecret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-patchWebhook.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/psp.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/rolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/mutatingWebhookConfiguration.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/validatingWebhookConfiguration.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/aggregate-clusterroles.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/certmanager.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/ciliumnetworkpolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/deployment.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/networkpolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp-clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp-clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/verticalpodautoscaler.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/_rules.tpl create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalAlertRelabelConfigs.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalAlertmanagerConfigs.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalPrometheusRules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalScrapeConfigs.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ciliumnetworkpolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/csi-secret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/extrasecret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingress.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingressThanosSidecar.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingressperreplica.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/networkpolicy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/nginx-config.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/podDisruptionBudget.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/podmonitors.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/prometheus.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp-clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp-clusterrolebinding.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/alertmanager.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/config-reloaders.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/etcd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/general.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_cpu_usage_seconds_total.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_cache.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_rss.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_swap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_working_set_bytes.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_resource.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.pod_owner.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-availability.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-burnrate.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-histogram.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-slos.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-prometheus-general.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-prometheus-node-recording.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-scheduler.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-state-metrics.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubelet.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-apps.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-resources.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-storage.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-apiserver.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-controller-manager.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-kube-proxy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-kubelet.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-scheduler.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-exporter.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-exporter.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-network.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/prometheus-operator.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/prometheus.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/windows.node.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/windows.pod.rules.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/secret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceThanosSidecar.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceThanosSidecarExternal.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitorThanosSidecar.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitors.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceperreplica.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/clusterrole.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/config-role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboard-role.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/addons/ingress-nginx-dashboard.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/cluster-dashboards.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/default-dashboard.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fleet-dashboards.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fluentbit-dashboard.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fluentd-dashboard.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/k8s-dashboards.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/nodes-dashboards.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/performance-dashboards.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/pods-dashboards.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/workload-dashboards.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/fleet/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/network-policy.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/rancher/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/hardened.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/configmap.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/job.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/rbac.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/extrasecret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/ingress.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/podDisruptionBudget.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/ruler.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/secret.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/service.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/serviceaccount.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/servicemonitor.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/validate-install-crd.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/templates/validate-psp-install.yaml create mode 100644 charts/rancher-monitoring/105.1.3+up61.3.2/values.yaml diff --git a/assets/rancher-logging-crd/rancher-logging-crd-105.2.1+up4.10.0.tgz b/assets/rancher-logging-crd/rancher-logging-crd-105.2.1+up4.10.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..cfeba7846634af4d005b7e438a7f5294bf82c48e GIT binary patch literal 175027 zcmb@tV~{A#yY1PwZQHipy_>sj+vaZDwr%dVZQHi(?&>?uq+ps-h|?Gb1YU zLq^tmerpwe1Oy7eKgTyE0JXlvZw5mN88&HmPF4eE6$T?kR&xzSPBu9e6*d`FD+_%a zBX=bQTV4rcD{Fv@&P~S+wt9+e({I#D#b?4UO^1U4$*ITj!qbm9Xjfp2MGmy++6RyR)OC<9mC&M%VjsbzF7Z`}46mW!w9H^3XJezPsz=?tHp_ zoTa}#k1_dlnoc~%`FlSbf`Ky0IGNg9hkv}@U!82>LbSIM^~S$~9%?38jx({QfwT(8 z%W7&I>EQf=ztU!hAC8Ym9kkd4v}5XxzdCGc0~30&H-!a44~%XtWtn-Uc*(T#s5^j7 zYjk;a@2~+$I?vs@-KRTch>1|zaL8m*#E zN5}hfZycTedv2jdr=!Em{`I1+nF$K+wmYaCZNmT6;8C@ukzjqAjh;;UtJjTCNwI5( zDg;!*5)(alGIqr7?psy2^W*K@*5&nk+_u}pUGn1_!Oq^ku3xb7NHgQlXHKzk-{83E zvQ~0ULvvJJ`5S;3Yn$)2-Wch1OFq!Jl!-dE@KsnM4RzvQ4M@N@1F*Y6XJ$Xieo@Fa z;VzS{pQ&}b-!3-LoWI(K{Ow45nOKnjyFdBY;%qtXJIFip5a<2ca~bYclilc9wKwYX z_KTk1-mqQQa@LH@g?#N(uO*Y!|1>Kn+c=Fu} zA=Qz5op-o;u|=$H_15>-;&2wfsd|<2=Gf`t@*%VwZstm>Zjwes{t< zD~g1%kP}+-yRpP28?!dtlLQ{26H0G=ayj!m_$A|Im?C<1G;nFHK^M`#E$f(8g`CF! zuChMJYe_)l%le!ca3xsT6sJg}!Sza)1zyZ;rNXxpm`4G{xX-m%LVFZf*2;-BN)dE$#ZL1SiK&so2X(|)U+GyH+E*45n>SmAr*aoKJ;Gi<1 zt`5jajZI)W2zXE#+pw3~S7Oc;*B~@Cc82-SD5spMD18hxxXB**xe&t@6JAFX=u&mh z3W^z)wIr-pN9a&U9Z?4w$QWJE3dsADz~EVgWs4(Ct*MJJnb_c&pDRdBi!;o~SUq>9 z$sSbWw~l=;2xVF8}w(bqf0TagNXH2R?n<_v`lb_uI$x zBLCOj$Ln#<_vdhq&&%c6CjaX_|2JL6S=;w=PR=*()+ch&5;>pd{(|tMxsqZLZrSqql zs+6ud>tP?^mc5ivsejng(B0nnO<$+yg}#?B+APKwt=c4+mfbVg?oxcxF-rG%{qKsm zNInQb*vD{9TzbZPlS248|0M9%bG`(xotv$a5Xhw2_n@-E?U4W<0wb*nNWmE^IQrg z<%G3g`A;@2G>cJ^BD)P^war*kvB}K0_VmJcHz1wotuasNHNp{5_s^QTzPF|Hkyc|( zhl=@>(T)1(QY@%WTxL7aS#8)2*UAweW5@{Nf2?98E7B)<(3p_&=x_WE`gK0v5MM`x zo8f|Xp3DV5aUIK}8{SQL=hYI!&jp@GW&o#3B zQsBMc1>*l^xVNQLV-fNRoABd(bY>(!`THZN~h_ncJ5XkgkTMSE`6 zs}Fca8=sl0z2+xavXTW(jC9&XT+-N;gFKV*xhXk!4uyhSeBjfWpWSYJ<=(bjs%uB zxo+PA(q0{>K}l`78A4AvGk(CogsE=qo_ZRruZ*xURsZo&%6NA_K% zC*A}*a2HNlnqRY~j7OCtmCi9HZMY~1nW@ixkWz7!oA3k$42yk#93)2E`z;WF#P$)E zj=t&YhIeb?kk8E0uicBs#&QeD!>J*H1`!C{8*NreE@73;Q-!)SI+&8%;6D=?^XU2Y z(T^uokKnp3a1@nOc-i5H2sy@^JBUiwYYO`J(zM}n1RNHEqVg`&cMnv0&}w#YuNULF zbpuL1S$l=VLqKF&1wq0EP@XcbQ#3aq`WF{m7++cJ+#dFO$04J8++mBQk(l(RB&h4#44@yJ$RePRpVb}o9 zn7AdgGe@%V>%Lu+0!#O60a0rCebsLOB(aY-&aR|1M4*AsNrM-pMUq#<4PHHPoW-J+ z;khiNXAzIJ8zZDVWY$I*o^VPTUJc#y(aE=9Q8>1}@pCM|qv)5-S9X9M>fIF(BNOA@ z9|Ey0&qF~>PP^nf!Z17=-|3^RzI&P(?Qwstrr0iaY|oK*vu|?>)f<$x?aC#BAk6TT z`6|*+drXUOSQarJTv|HWB?`*Ae)@Q%^`3co1EVM;Vtlta40m9;fH?dGtUtL8QdUBX z+4h082r(|9p#r)UcgSJkHhh0KQw%W*v=P3DsUS(cW32)gGX}$MIEvB+DWNn4GX^PFX=G3L1cS=`xM6G?SG#W<0EVx!iLezR+T~Tmer1%)R5rZt3aNQ~EP4GFFUa0lJ+e{ifBzu&>Ph3tN5Q$u>zCm|#$@N`LS79iu_r?^ zE{Cpsl%#%EkZ2q3X5 zHj_H=YC(9MUpJr<3`bHGVaV7^2fmuis1f=tOdD-AJ2W5=>4YVb5n}zej<6=xfv!Q( zj%9t)%aYCQDsQuf#p)&k^c>Z7TvuY>o8~0RPnYRM`Q@#RkMP3ixmE;5zmCUpn^;20 z*WJI^YaQfwu7!NfAfBu2R7I-^`i9QEGKr%Rj)(}Z!Z&!t(Gs?Oje%DgZK<#0WiX%z?M@f98e>ai6beI0VuXJ?}& zyX6)P<+Ir=z%<0D{`TE~!GGuaXjnR&(G*YsIaU!uv29}rt?K~Rp=?zz*OgE!=&KPS zV@uWH)2vV{vTUJr?9a1=w4@M!^)WA?nnFR5F~{#lUnoflp2DiYN8oc1Hq`5yuC*P;W(0Y|O^`x~8f{rcC3vJdkP z?I6dLIOa>(_|enynt_GBzY;i&0Le1C1}`jWqA{$29B^DdXs}#_v!b=*^%{LT^DZzP_nV4Q6_eGtOope_FcA=_HLxIGBDX1c;38G#Ur z$7(t+9e=%sblkpF|Rqodn zz!WL}71@Ed;AH}jWO;}8R0r?A`oX)8-0HTC<19?JC z=Oaaa@KL=hP~NzAe^-F%#}u411g%fRsWOQ=$J#dWu*JZ(FcQzf3U4+~b; z{t=ht8Ugi@)|9u3F_!~nYwOTJN&v#wW&gX;i`_+CHMhTJ1hYLAgMrJ_BjJshDl&E# zUFg!|c@l4pB9i7Y-I-wNB1k@*h+l7_CDVH0rSZ@y@?bZNW-}z7iTFJkzpxyVBPUJy zHS{e6nB3hI+fel!7~{jEQ17GAz_pUE%J}2cylA2c@1hB=$*uR$rDR_(Ophkc`mbIc z@EOUz>_6BO*?6Ulp#)R*yUljg-MW81)dbZ$i16$&MtAGoOg zV)R1%>c|zj_AP(c3RNlxX|1&1YhvID%bfFyn;?;_-YBBlEl-26Il`Bu9=13%47%G= zt9UJ}`$~$gQ2o^%J#r&CjBJS6uEc&9e0n#T#2hRJ7KC1mBNDdrfw7^U0yE?TZY^(~ zPYv-`yMEDh$APRs9MamoAzRUxHsH#bSa?_PZ z(yZ1$o_$0}MmjV78<77t+%tkiVUJw;1SBjy0hNJx04mz;j8iFhla4*v!=vP&O0VM$ zwp@cD26C)+$gqeUQ6om2y3*J$8h1au0;Ht744} z0TU53%5#u|y5^Zsj7MbxO}mu`Bf$Ks4%V;9`vS#N;26Y8m_=|OiZLF3O<5L%US>h| zfx)1fF?$6J>BWc|qS4o*r-=Wet1dq*cR3$L_F|7rV@a0kV}NXjs(&NomWn0IeoHczQ@3<9&p^@+wC(?YygKY24^o+7f}HDMNF$WSY#7fAx0)Eu18#|4s~*M zAy>WFRPX!P$D4E6A}|B{%C_s9q#JgaAIQe%8f5a7e3(*8xLa|wGhgWwSqjQ)M5Lum ze$Y96EiPW&1S#d7*8c0#c61C)zJlqT&YE#UEtXAL|JFSzciDI@N|x5!j%UGVz|3Oz z33!1D65f7uuqgK2S7Sv3GaKX3-w=r@0S(Ez%kaS^Y)Ea!{LEA^xp6N$yHXuPH^*+2 z%BE&1V$X!nbq>{nzFmwz8?@iXcrK{MHdD{<~qYQz-H}_2*)eN*+_@t=e~%6fCXld#9B% zFj1@Cr9RE~@hG^HMG@`2cu|g#m;c8)@|~?}TvtW(4xZAlJD>KahkRqc>^~bXSpuK$%L!o-tj3x19_xd|2xT zHl0xusz_Hr0^f&XS%8g+9hZq5i}&uAiI`W!ip>U1>!NTt*b=No=+;LtW5!K?rO%>e z%%deNqGc_kWv!xh&x|H>Fm=<42CqXx_Oo-wF6H%4lBonl$onWb1nD{+1?y|i*~l@I9+kv! zw2ndRpkc&fRmuRnk%1>B@ko7=&gbkW@ld;I4nbZ7>Ro41@gd^&vEK0lF;=UnzTG#D zyKHA;7&{L&J54e=a04f<++7CC?+ju&GJ`L~f)~;PuB#f2*6SK6Ho(Rh^y!TnVna~K zUhhvO+SG=b&5I`gUAr#aSHFqZmyu|_qhMqs58VKp={pj|+&;Y$372V^(|ucp>32Yj z4|JED1DBD|{9(6scg0)KU1llpW{((^oe^(%=gE#xCuyhY_^_DO?%O$XKZDaRG8ebM zSAtjz=k}s>ruw~EI-1pPOPYLPnwo4Ile(F&KNKaS#%v_WbjsQ^bAqI^*eG@AJ|mL7 z_{N2QcFdY=@kk<>EO%xBpj#%1&}7+i?xh0X)kt~+y0RAmboPoq&aNnPuu-F^G-kP7 ziLNf^)ro-5T96w59OEXl_Xe%5Zl7bF!Pei6N;5_Nd$Y|9ifrez2A*7NIl_b6S%wcf zFAcN7u7B?IRf8H@)KbrMIS9n{*R%B$a7Z8tr*)U8Xk}qP8Iy$?9*S{qL=<&1XL{s()lhp1fnL*eL z)2y%JZhFO^zgAHHq-eG>{zB6DI&4S)o-|?v|3kQ7HFS89KXZug;trVdU)a1|s2d%b z>|3t`p`23JE@?WcF4-P%t)s;-iGyY6zdHyUpVz9oKA)3^71KIhZ%^kn-JKs#8Mbu% z?H_mRDK$EOlC}8;fLMl@K35M<>aKh?ko_VeB1|R^AdCCcgXbvU9z|KaW3~nVy<$2CibNqTcsA@xAwoj~_Hx(!;XU zpJ1jBD-oq_zwcd=G_8)!7W-Pwa84#nwpm=va0$MIAdLoEK7W|a$ewR(KN ztKz$U@f13TFjat~jD0=I0mI{UN!d!oUunm%TM-GMGrrAWWli*bQ~aS-vYhLxDIaR$ zcc!ejJ(kAf!gNS$RHVz@?gDlh%^kmBHX)mIg5sh-it3nx{WhH8x+%XQEe_v|?r)en z{`_I_j>DUN7{XQZ%7YuO{)Bz7f-a@&u#ef0`9nxvfJl+8a~AOfsX?0GsIi22NCum# z2(hRb7#Wb`n^;MWK`tZ3|55ZJhh&^`ow_Vb6~s#m8|vvJ)*2Hn7kC`KMBuKm{t{Jo zv^>ZEaPK12T(j_=kOI3k;-3BnQ^8X*ct;?>>T|q}*3sK~tmVkVVSmt$ME_g>7GdJj zyayCz;={xHd#9!lLU#>Ge+)^tjj0Vdk9kX>!RM~9+H8ip?WgBD^07kPNCY~m{93BW zAmb|hOpHz3RLWnz_Xb&7BNzLOA0kP65NMO-h$mVCPGU6GhwgcX^BgZWht5@ZM)=tlg!k~2$XEkXEXUC#ff9TX+ zZbgP(hGv}oaXdBc?%AX{RSlWe@2+TsAabQ%5m$0bI9IgtOd6spJ_O1w7OS}8ctX&M z)j;TI_2pPxy~7gZs;TtdN>3m1nJd6vo}hKtfP~ z3bbBWuR|Zcr_4_OQF;nH<^K1|(?%5PH*PI}(sc`isn}2L8F)^G6pBL20D}@#Zove> z<%Scm6FmNVGnLqGsgmiUDj2EoP}*ywLd{MFrxp5LSdZH#B&+=~P{~)2(y>EnvWfH@ zu{e9~_{0*2Tl+!_G;lJYB)=RN&NW5gf2%uzssVT-Z=BABu)2KV{Z14d*(OO|t7+}K z+N%(usC#e*BsL>pNjnY) zgAeL*DWR%74A%+tyt)fd9U7T7s9aTlqfm`!b`l|SbVQu5xzT&8js-j)s>mKIR+W3f zS%J)_S?U}MjjGeN;1oMeducgX%S&;px~5)$4FqOr+UNIDqA=|BkVDuJ5r7&GF?3`s z{*k^SMPxVh)WJ70IsONS6EhmWg&UM_i$;n*w#%_zNlDHoqGT!jW+4@g!S{>L=M|8g z{gqpI0xSRf0gQq&-R+wsEipbHJg4AI+d+9$c@xw@`C4W_@RI(Y)+0b`dA4L+E7uQ^ ziLa2VJ}Vh{KPa!x_QI;BTD~(?z0j+J3KFP=G zAtS`_!4Jn&kjCg@2%n8@vZr2q~DNaBjh*xG=fo1 z%=i)nQSB1{!1%dtzoAg_zbM3(iHR#e&=YArq$F=(1dCLR?}mu+4lEmtn7@=2>+TP6 z7mVjllPL}%%|HQe8^O$S`G-h;eg?et^C8BN8G4|uHJ^&bfLWnh1$zYYuDuj)C+%ZQ#}g$L#0Z3!m44#w+Vtr~sUP(h_uD1I)b_K64Xv`pkLw(5~@2 zk^nQS%P+69tIK>p4*;2~tIOmWrh=Sg ziH1l3g{H&PF%K7fvDrVn{Cq>AVf=$4-zg6AG;mOSvOT1SuYcx1kU~jNITcx!WekDd zfsG;By89=f2Td8dIpH=yOm=KBv@y~Es|?I3_zge%S6Yv$=a ztB$E*&OHcyI-tAY`>$D>Ge9EFnb<2`ZyHxi74s}*om?zKRfT1?TCD$XWmrQoA9_=qg8n?rET50{`ZgPOAWDZ_83 z(xXgLL()OFatEbkh##k`P;uN~A-|CDP|W^g9V^?%BviD)|FglI0sg=?U#-P{f$B4W z%(zymf1t2O>J_4(rw z-=^@>XMaE5Pk(#6-}-#Lru=l}zyJ8fA2rk8TA%y$(>XuA+ddz!A=}kkp9%cm_t*7h z)$cx^udmy?oBVMS+5F$<-*>Xsh0y}@r}58b8Po0=3Ne@zSd*8VnxwQFTt$p3whV*| zlSxO=bb4Ud(!C(}%k))8+zL_v30H_`Z&B5WU2_&=L8`o<%DiPi=CO(B-jq<1;`5E+ zt1a!E5>ufbYldAf<2hD6aOH(O8hRKMP|Ax&2u?Q~V7;&@MQx1YJC*9j zE1IyR660wvYVR>44Kvy+_M;zDiG0ICVa5Kk=-jG+ z`u96!r4}LWLbxKJG{0h$e{5uVK3N0@trJ=ax(6_5G|K4z)0cR2zN1)V+Hs3O7eTHK z#>*&g9wEH??6@3pj~E3j*v-SKF(C%mu8bt~Ql!$-4L08tlC;_O2eVqxP@#L4+wdLk zD8T86ak?c2uzQ1y_1*&E@klV9k&!|q$< zArQL3oomE_2v?aXE(1};CWpylaj1-2ej5;zw46YYAz+|>t$!bZ+%0UR^|e(`JXYf^ zx%Q;)nh_%=MT90vK?KZOioH3)D3~10hJs@&_gtEokpQ+LGtL5&SU3#;oY#YjK+csS zOaqS_-Li|$zKPC)wJQU$I3kRm*g!L63GKoJ7A%cB3i3gLAKiIw995~p#>pkAY`T#W z?g5K&RsSJ4Q+w#Mnc(h?JRJ0aRMztOD@9I;n4Z3kKxp_^tURp=2f3X~c8-#bEGS0e zvHk6<9elCALU8y@;Yqw;m)oW~p%Av-VCwL~RJoWqB|gJa+KUrncbl(6E*O3o@4St; zrLm=7bYNzAL)RSLt1a>?o)Q_%H8p?%NnWHoAM{$-=lzBc($MSr7NagQPUj@GT2bZq z5QAeeA)(ktwhiCF=Zb}c;qwoJM3_yDyYQA*$GuWKpPb$Wv-4y9_fgER)f z4*-*?7k>rpXe}f(9bNHyDnKm;BS{EhFVX}gLnkg6oD97I{+>909V>J9VAgC6+4baZUfz)FhV(rJ}Mo5Fs5CO zRGl8SWAYXE*P&8{Ple+8Utj)Q_q4^M@!>oaCdY|~F}d!SGqG(d-L@8|p_!4qoBo(! zBE(coZAgZxAOe1Zr@=?=mTgFxWzHEp<<*N-G z^8oZsDh&0p-9awvd|;GKcIV}e#PXuM>j=g%dUKd!@JLIa%oec>in$T)4(j>%V$JuF zwb(=LZ0ky4Y;R!<_<;=Xg3^;hG`n(9pz=`K%&d zS@oMO&|#VLG_vyh?d8_MaforVEvk_XcOLi#1BO4*i=^=Y#?&Lcbp*5XVc9xxC)pl0 z5oDHX1mf3R?L(29Igv{dc;X|h{V;0+Ke;A$(2@sjZ_U+b7=ihpyrCGXgR8o z9@=D^CkuPv!@{59k;P~>`~p?+HweqxT2QTUr9o9myI~4+9At#d=7h6H++wyVW|5#- z#olN}>eN@Kqv=7nkB}*qdruaf6gEeWp^_CC&>I@euWZG^SvJ1qb>i&xds2QYn zllIM`ruvCIps;g3CmC~aJ7fx^a*U>r8ADUu`^ECmJy3>`X`Mo!b^In0Asls`bGq8* zs8s!!F^}723o{PQ+v6(i1o6;IctdwS*2@><`XLkY+UayA@Ca+{f2VdG{-E-5NFP*yU#MgPDl|2 zqE29RZ*SaUH4j?qq;mX~ihOn<(Jno+mKA?H6}a@Bz7Mcxc}{Jp8dWZ@uXeMgZ<(1E zA1Mx}Me(KIWY~wkREd9WXsa@=YWT|twAjK(GRw0uxzaM3Qt|oFG6h&0g{yd>t&jK_ zGOvmq)JJ9Bws?5RYKh97D}9XiF!w6fG)s~h z$k)rD-NXm+Jk^1JDTY6x6NoSVM4*~V@4{kie;@3f2?Xme)08lbeiA6ZB^Y2uSWmxz zIEt{MYVuR~K;JO40!BP+<&C7A+Z;r|J#!-hZRaJSS-&LgkX!}B6FmZJWLWQk4Bg;p zc#oVs>1lm>#m-4bl-Rl>B(Qxwt>ttdhd-vh-eP{sXag(6N1r`urQ{^*b_GVv0BL3w z*WGM|UWwp=pJbFK!R4g$#sWO|4UsGIe%y{q-)MbTF&Om@Hh+BzU8Th`*;ol=6-FaT z&@qILqT5y0u29MbmpM?cs=3ee)-fzok&8EaEvyE+NlFLNZx3#tGJV|9)CAJ?rR}1~ z&GxDDVqO%P`s5NV>Uf&;hOj089o>KZQ-xE%(u z65Zv8P8Q|X>DE2j+A&v7FCJoaX2O|79oW>r-@%MFr=8<#yON~TMmHFApT?@&nsc^f z_!s7B$Sy}3je8UF4TL^4pIeYy;t!{3lXHPL(Q7a=dFPI*qy?2+S6~=SZk($*Ic?2G zuE?f!Z2Sd!adtp(Le-Y$x}iV1>!{S#)h=(Ji9!5yv^@UFD1mTnpe@VsA*#*?T@uU7 z-7clJ5xbNw^x#-dZ@n&hE-StMGB=)pIZeYPFBjj-$rgV5*tG+-poygTc(>P6Xl@$K zQ7(O8`eaL{HcHz^AKmpjlP=Bon?c_Jek8gO>mhXYoiXgbQYrTRUbJ!_@Bfzpr)+n4 zJf8gz4EQ{yrt5>I-76H-EYkR`VSLtb^Sgx{2pt`Ly6LwKvx?(SM!TJ83Vr$8T*vNl z@FxU*#guztZCF{(_fwE{1(+`vh>x1CFPAa?B+oTBrJ+fyRD^uHQvJMU%V+*8YmMb$ z|GIa`PT%Fx!~$85OT{f6Hm%ZJ^*C&}+M_s*?VH@7k7goOqdYfwRs~J=hK4(Cdl~Yr zQ<`yAQ|0%*|Ec=}hD~q(0mGY;&y`dEfZ^+phkwB^Wu40QKVX#b?YcGgx? zpLThkt`{ZUHTdEDqI2{Dryk9H2x=VtX1R#xEk&Vzo_aMx$G`K$NB3)^<}u@v{}Ma! z8SK5Nj4YR#)%x*WM8FtqScCUQg>~)<#=Y_VtjlMKzsYS>gx8e*eURozzUulyk#&S! z_1fqAY=0^zq%t~h;tnvV&F6EmCm^H-3FkMF=Q1!{hJ+#=4GtF;mebjvBb7X(Ua$gu z48y9QFevt7s+JvOYcS>p7ksh8)0h&ANw%v}mz`%22mcpV?o@kliS$9X9q82eYHw&O zFVf>?X_>p7QdDinI!vr_IqWKd^<#ldkcx}az7v=ocE?(n(7je^nlbYRo99t;)RG!( zrBpZ@X*DYB(YTr#Rfl%7@9YZ9!o>O|KuFm(n2!J7jV)4j;c;sDsL6IT%z`>rush1- zp(9!yL-im%l$;LpxGQ9LjgGK^)MX#)Jf(uavXJg&R&>2?8Z$dfdSP^^QAAzaLi*dA zXgfA{G3w!EbD$4xuK9l2#71SdoFEAe!IK*XnD(&Q)j|Hd+7op8u3Fug+-mQx`e5_Q0`D2bl152addx6Enk3qvU zPpY?<8Y30W@78BCkV7G-1euL_yS7Zg79xaO7IyeMsj;F+xt@pYq=Pq5YLKp^Beyy0 ztw9#gR*c6Ola21Znrly`(d-O=;}prOP2SUaISB3f07(Z-RkeYo$+fnNV_9tYyWi?f zQ&BBSymzW>ZA8W@)_$2?inj=>d;}-|0#ULDT?P+SS`J)Z0+A#CTTS-2oU9NBNHYXg zt%SK)3Y<4_8F9iNu0_LYfEAmd8Z)qDoV9cqN@YURP`|vFBgWIdYXGjztCz*JOEX&t z0s9MF=yT6bJ%gZ069R7T2=s)+-K%iw8W6Hr(5=lsY=P50$_HRCJ#;wvZA4hBFxrD) z$f3WaSFJEQ)baxuVOfMng#wnd!o4d?h7ANBd+Blx6)DU2z#)k<KAv3Sn!zC9nBf@(V1J+wh$Uz1aEO4<=>Ty81_fXGspljBlDb+j zxpfD5a^q4_etcDi!WPrIZ^Di5d=|2(I)iJHP$%Se+==;OdSeKxHMN~&Mv6hAt^IXH z>z>P&oZ7V2Dp117>$JoXwqPW4bGm2~bO3HQin`?zuKu$ape<;R64Rx^rf#^`2ZsC1 zfc1ER4Lw-js2LJDfdkmWJgeve{Ej+%o?vL)$ifM`yE zB(ACW7gsoifooeyMZrg*DAf-@$qc_EYO^7W?FTAk{n9|02v(`A&bx5*S47=%N*HUe zu#_cZJJnuIHy1}2p7<>^Xgzi452;hl6jU`PXelk!K!3DIn&MhQ@Hs{nTH9nfYvWN4 zTlu+;5K%;IO0=vTf!Y<0s*t!i!jZAgdz2$tMTS4R+y5odccp}U7Q#g7g0e0$30wTVj*7Ymikd669Q zj0u%4kwOfpY<+$Ab?Owco_9q|SB5%KaF!gJD>1>KZstqk5=%3ujm@ls=4xwFn6e;T zioGnH$-LYjIy%JRvK|oJ>dHHy{fh08V3OFsES&D?O&lx^uGb_EvG$y+Ck;PvDlCwB z1-SP>LjQvan?m|*@%ResqwrhShxNNB*2dF5Z+f%z~gBbH%SGFI^kK0@I`26kg2xUFJ> zwr+MXL^jZahKcjLjz&Y&IzdAVYVj$3+r2*2LgT2I5gZL83}fFAfu;dPqH5lt!VL`( z4Mqqch=cWRArhwGgj3C|APffL3Bv*21AFTrqumPFsI0I}n8AZB`(f`|c4V}6$T-Z9 zF@YiBmj=Krh{!R}bHf~c`+%AC1=C7>CtmcVcWME5mwI?%VH%J^Oa}7W1#qw)7`WgG z%!gPnyTs7Nxg8JsJ(F(Z+3DA5CXc-U~laqyAh2EAbBpd$hC>lPS^uCVFk zg;{>p+HlxN8Y_9R+e8{JWd#p80)s0+83yYCv=mJ)}FZoJ6a9eg@d3Ap#kFB zrW5!Jsz8#BVz9prI3E`38A9VC-NCK*M4nre&wRVbQyps6@lu)g!jr|A#`R-}6d>st z+&d2$Uqog)cr8t(c4VzgWTkFoA+B_vqSKG|fqEC#Mvr_%;88QZ z+itkQI}@QKfMRf}O}PJ3quYV#^q&Oxs`a%nQ_-8iFk}KI4kcjXW}w2sO(T4v1djo( z2bH7e!Hs9d2*auJ3aBe+0Pk1dmDqhG$cI;pnF-~^qm1SOs@sF$0x`c+--BQWAP!f% zH3}z@hcTz4ztd&i?soxy*gn^RR_STW%k%SLCx8}lS zt)RV8GJ@%9vnH$w#m?PBlI%-ri=1Mh%(DD&roR40$bhXjWT985d`8--w1~|KnUNXk zV36!#SK6BTzZP`2+YN@2%P~nTU|dUwmZD_r!%BSWWr_mRZv};MjVmY!b8DrJN7trp z<%=2BlU)H1|0Vlv@SNoR+{U2jKSDx`TXl#`thIHHm3B)bsf^L0+UbqennbR#SZETV zP6CCh083jyhXI;7X(xKl^JUKd=+8hHU3E*03+g*nnmw6OFoA6=C293RL^_sg8>Gf0 z6rCw&!f*AZbmB5L?;v;Lv;q(%d~d&X^^`SP-RK9Wq=M#3+3M{|8J ztdIt~S2>SZkS+QK zYO<)`0E@w0To_z-KjwDb9ab?;ia1+h~9ebW%M>ZXA zX{L&{nu2AIpt@-+FLRL7r^<5nZ8|Q=ndcK$wS8`&Ku`)2k?Jsi&Q-=pxJTb$VS4a| zJTbeKNwG*TJxDNbhUC@vQ_23hP}F34I1Fey;gTf_A~-sOvqtTx2Nl+ki*Nn!y`8m- z&$?eY)ViiB?4P}5b>)w&I;M(b6L)fxBEtBK8a}HIVGZBc-@N1X5n0wY2uI z<1mk(IOCHdTu4i4FwnTLBHcx=SnMpDSDq0g&U5b?nig9*qr2+qPK~`l*h87w1kZJ- z*KRf1U=T{%{?$)zHcetb>spVe<1l2#ql;Tq!bH&ps9w5}aJP|$;%|LHItXLIqAW`K zvCt$<1}UVibpfjia7BE+Oqiu;K-tupirYMn40dUn37Vr|C%j@eYzK&WYv-@};AGWY zto8N9e-djRCpOUv5KTuR;d-YDw8J~YG|755Z;cd3 zGU%6EesM|^mHQ5EKVHIHe!ybEV-@Xyi4w1u9eiG!-VV3gNAMFHSHeGHLhoup&sDrS zjh+%2@i#h3z4MTloI(57uz`&>gO3S9qO0r-#kMFO6iUq;4_CSEeTd5!!1hswa3ur( zOCSR#fL+{^y38Cx7rUp7r9;*2`VcJ8!=*Gr8ng%P5LoN@x`1^`WIYS`kHY2z>k&E2 zYVG6uwvg@B74h96pqCZkh1PA{m@}Z25$|Dr0}QYt#-K_GPg!KszZsPvL!G;vLWRi+ zG)Z;+STpAtHT&FXYaCSY+w+1U1OXCMH9B1hhWWUqQ3S)*TyR0SsSX4}v}q z1{>Cu%w+~1P@PA1)ekSU;VQNf;{7+U+VrRv_HP7Y-K=Hg3ODI&>V9?k5Hj4?7ve*r zeabgz{&~e5=<{}Yh!~DXi8F@51@4l*nqq?L4DRBHolL4jXbTJbe;2rLT|8`HK0EQ? zgu}Y0Sb;b-+c)|(dZhdC?x1n3*|~q*q18tmo;D}vErmZo7hm9YUBM+t3W3bv+7Inr zO$x}7yu{hO?fb6>#HQaAoPUYPlbEE^um~V=OQ4-rM`6-KyKZ`f-o<-BIPZIeIv#mo zFs@<@+j!0}JXeRvlh=eGsM>l43&QEb8*X-;?9KwFULyKG@ls&S1KYnLAe4Cea`28q z+v_J@=G|nVI}}->$^MU;)>qbfG{676*FF(%&q%R!CmN~UuZ(SWA7of#DEbk>lu(~B z^~A4l8vABcLcPPJr?AWz9@%>!M0oFJco4T~Sjg7R4u4h-e^I5J3#4cMp*)3pbcyb_HP| zlvEf6@Ch=&5EC}xUb636AQzH6mBw9*wv4Nv9IS#Q&BBYv#(#byIzxRM(- z>KF_TLB;LugmlQy2w&(X6{kJ-5O$&gx*r!o3r-!xsY~0}3_4$ehjL)38@L!5@flA2 zBGt{c=R!{4m#FF9pt~00s@ttP^Q}9VA(Jzaqq7)k&%n`nrey>+i#B5m`b8&7YqUiI|=wu=IQj0kI^oNPLW?WpyV^f{z|W<Dvxx?B(tEz>is(|^emGW}niy>oD7Thu)o+qP}nNyqARCmq|iI(EmlZQJIFZJQl+ z-0$?geZL>-y?zuXso@wc5R?o{$;HPx_#XGnKumti#4ok|?6auKHhj_}Ij6fcti!jp4I(-T5f2 zSkQPipP`JT%#cGG`s4b~MJ0%9iSkgt3#bryKo}08I>XEzGz_BJf=FW2?Tul`mKx2c86Xfo%AesVO9FMh>L^&wiUq&JM!@XK;4729)J zes{Y)q?o>0r;9C&%X;w_%!?V`(VeHGr#R_I=a(_e@MP|iLfl#EB*4xY6 z96|qBnd)KmcPFwCUc8g$uL?!I*Oi!vZb+hgPK-G>)&itWiDH%Cx6+sDlyNS|i(d&Y zi5R>#R)eq6{Q8N_&dB*PF!n%x2veLqIN{;}f!nA-G9CEAbvO~@PSf6*<^&&rpAo=O zmp^GqrEu;Om0(+0SMC%EXPW6lFa-iRMg``$DUY%_?>*YiqD5v)&5O&;iHK&4w%O6# zpIqA0?KTw2sLC$AfODlBRfV6iho1<1d;B->MIGV42 z3@1AEu}tau2#bE*6zv0E!_alK9f&XK9#z@)P81PdQQ* z)mL&#so1>1-AS@hXR#y;dUFlJ>7n6ilAhmPqcb09_EHb1SN#08X}vrCtnRGaFkG*} zw4R0Sbr2=?WAOWsHS07ZKK}Sm-)C)ltD&7Eqi&C4)i1~1(mdCe;%^N{bNvV$NM?xX z6>L&Zusn@LYA#Gb1Cp7MW5IrmW&4Lz4xHLHQ>;1fE5!Nw!y+_@4*ZxUxi3+mlcv!a zk_exZNP5W#S+=PZARDmIHVkv*h0BMDwp*M(1TONGg4>_V7CBxUoB$S73qe2h_`ltQ z%OhW0=wI|d7Y*DU)U(fYly#>Ne|4&*m~5&On>5v)LZWKrr&@$P_Pf4|>p0%i$dv1{ zLCgYR`e-bz2~%@qeGwknbYE98Ev9bh_}IaOp^>DeG-L<LQhjNA1*R zMBzO5q9MHLGc^2~PY5YOrDxD1V8PN3QLI{&AkZFMusDeb$$U zE!$pB&#Q+iz<&-~a!gW?>p-IF{e@X1@?d<_OtFLoAFrp(D32YfhAN7ug z9(>cWwY}@ypD)rUZe1Rm&rNO&#u&Ey5+@X&1S@*$Rm+d50y++gm!RfkVP>$|W0|Wn zVCC_cWM>F(7iS{=vobMx(Qu6!N1ESb|03?zxB|(fYX+{wxVYyi^p4uAsiIrC)vhn* z?5p8pBkaE=e)+-FS|@z<`w^Y{{kqAV1N~RY7CbJKS(N_ER?Kug0HZufqo?xT^_gKJ zIbu%X#!zacFPyRVLHlP@l1O=?!pl~3eidmX`IPAfgWFzLx1A}DvUt@}Tk zxv^TLKl~I|=M4x2^@%o)z+;NX>oHGld-DeD{%Mg21}#R0MBmtgsd%=38oeGRX%F8~ z8NLw&yP-8Na~iT=tszZ%0}b4-xOV^@Wgt^cmvJv>vL=Idh7X|&iJVTx!PcDW_Bi3en~gdl;eZ98E8!-%@F)s{dNfFr4C zcyC*bKk-NHXV1v+Fp_iG=b;-YIJaI8mNO(#tCUhL+ue@?;b1&%V9ViHTS=VP+G9i- z5pbPtYtx6;i^na8JSkJ=_Bh9HoqIuT-PpWBf%(`J0hgn~CNcAIzB)X+NfP8w1KHgj zF7G?*Ah5Nf6xE!P7%8*lo1_Lr77P$Qe6>(-eK9jk1%6iDI)`(;=rUY;Tz{ujaTdlGZI(*y~wI8}x!UpGE(Q7j+cUR&U0_3kpbD3J~q3x7Vz8C-5*LaZ5HZ zdh`vpew$-JZHw4t4NEj3OR8dvw-;zWE<|1SfE=#HJ*etJ9Dd;$WjF1+r6nH6DcBi6 zik&zjhzmd_M4?2dlq&cop!}}_4tgkq_8mHGDvLaR@XC)SjfNLbP|0&g55_QT|o|bTg2CBUv9%#cV&(l@ON?O5sXI<8EH4G83r`)!0B*l?;DDc zKVjhkYxP2j+Pf+5mB22+DKRI`gkD>#3aR#$oM!Q6|W|acTQIJ`U(%~GdAPxX7 zs_+(Qdl@!7X5FL;d*FLv-aKZ}Fbfo>xWV?<{AC!1xxkm8$ddl&rLVNyEMp$9bB^Cr zv|JG9;u^BzTuF7?p^pJ_g*sj$1a-*A0MxM1Tox_CWq3prJ$wsC!~l(Mzs}iA3;-#K z>sqLjDYXiV5J~h(sM8V5pg5kX(JT6WVV0fZs|+C_m|-_?1V`j92Y<&RB4AwEc6`{n zh)#=Pm;)TlBWdt|gAox}IAKL>7Xa_I0o`2U&47D(v>I<6O#;Z(Dyst(pH$T=_wKWB zwcZ&l!`bDi%h;NRP4wI=yQlGE03cMI7eUH4*EC&&bEbH*!6+3gOb8>o0s@ux+9XY` z6?J3#e0;LE;^=e1_W(q-QDdDD-~Aa7?9E_{FH9kJ6Fn!IiTplTOAG|U*i(A+>=hag zm+tvRcq7vx6KQ@Qu4e@@{<{;Bf~kbd(9c_q%~!@q8`ovg61@`!E#uKOoe1pmd^0+KcV$x08BRxoX8pvk za^5{tZF{0iP(0gSl*YQg>7ruR(AtuOQU$))AsokFnLafYp)+=c*U-wyDYkjwy;ACe zIs9`VH<0dzjkjVrdz4IyN>+@e+qiJFpgajl7zcOOV@XR=NsoAnBR-mud~c^Karj)a0o+`DBV$XvF9H& zuQ=IWnyE2z0L#|M4QNV8?|et~IdOXF_-%Dv@^hvR%jR*cYMC|E9= zv=5UnH6JfTeaGcf2& z(-=Bli&VTy{l&)OPdg;wtkc+2MM{}jH`~TBX3cGJh`I46O!pUbJ17dQxW4~EC_8Ib z+uz?thnXkQW{Jo3*3Tph8PLnDlj4H*S@ER^7C#-=Q3Iq2xvrS6a^jJM9GEq`eq|a# zc93u2n?``c`wJ^vFZ@jdA;E?(SdF13ayLkiAfr`M(_iE zeyKtlWoU^piLu!eZ`L>bdCmSrR&nPm&$Ii}ObS=YL@%tw$hegy_bZ=!69uNYC%ZQ> z63Z+{rSS8$b?gv*eOS zeXk?D$Qp48Z#H?-(e%Y8azBHS;im;^b!BY!{VyN;lh=3+H6ly1ow1uzUc!Od-Qe@G zdEw4nqt-~8X9k+pJCH1`U_kU#RY2`bn<`wVv+bv2HD}wT*|tR(4rg1=u*j*Z5MujG zt%qckZ*17Ley#Y=<7_$fMg{vFCTaMKCx!>>kPR$f_?VKvCjX=cnf*0E*``>DIWC8Y zL5L~!brqqTS#|3n?wa3AlKbIa=Z2L45~6D-t})@!5tRJ)qy}fP!^b5~nI%dV+C zAxr)AhQTvZO`7&k%H3zP`i}92ETZ!woVf;I(Beb~8KV*>^&zIT+21vk5RQ2bv!rb8 za8MyB*Jc!P86m24Y1 z96(tXr>QzHCgscFu3?i`P*+xUTtefz*^W(|bh-)s!EdU8R%RU9f#!pynNO7N2;`L8 zjfVJhXknOuvO=OxpNYlN3gKI<8Xz zhmM&9(gsOpH@H+@*x#rXxyKCTtTAXMt+_T)LM$(kD+r-I(SE1r&gDgaLv}M;+O1kr zrlHNNt=fms>~N`rk5R4!tS(4ChUt*0PYs*xeW%Vh-f9nwif*h)dB-Vu^|tNWo+>Jv zQ2(+=QjF?Nm4aJZ-D$;)G;h8+2S~lVa%^7pcMVPbzo6RIQUgFb*C(wt$@JWa2^FkA zJjgFN99I3LABnoTyW_|a4QVbEbuW=}Jrc9Mp!1dQ{|4ykQde;Kmh8{hQ_&K0-jW>A zswB~KOJlLlf-Wy16m1g!1X%sC|4(WID+F@!O?m-`5T2tm`0I(V(K39g$wvRJo^USD z?-F=$L^d0_k#W06;`I+$*ts1IgNGvGoP__*GiN+{F>#kkbY^}+{vZUr*t#9OLUnV*{DnvSM2B4PKNUdHH zPH(Z*{L3^P!ctp<&q$(3hmAEGULBumG0!ZXz9xH2UI=hcE;zlhcE(m#3!0TU@6t9A zw}r;8#VEhVp|Te~lJ}{Xy~8vS!;UyhT}oZ;=RT6-81KW3><@P^k|Mjd*El0O>zzJ= zOYumLJgY_DNgx#QPg%tijcuw1Oq_4D;IU>!Yh{vtJbXRHccnp{+`q`uN&>Fv=9=Fd2hR9nTI6CS;=+nE~`e;#BU_Gspu3aIS z+@^+3m!nqvV(hBT1$|^}5_>#u16aAXX%VI;_>xBhEG<}2Q>1wADP2IOeOk7UM1&dYl@=lU#B5Z%Y4`T{a@E6e(5uXXhT=-L=a7B$f?p!s z3a6ieMuvsJEkpt50<YvCW+UP%55N}q!8XJzZW+IqW_-+c^ zvL}jomBo^Z6w}Vb@zcgqa`4^641&jAzl1P}**?jOowj@edb}E$uFqblye92GRCn0CNY{BeojIA1v}3*Itc^(ik&3q)T;d(La7X`L zxP{cB6DSp(g%L`Weo^%O%L;=aj_WI;K&0B3sgfHmKu?&=M99MJP}|OMa2_6S(YbWq zq_7~{_(&P(5gvUUtXC>|dY8K;VH|#`)DM?;&dikG%Y4xmKfq1=z1c^rd>kCR`uRAR zgkiyh6jJxBQzQ$!^iE7N3tKWbZwfwewDhk327Dk3`^EjM9B>C+UQ9s>kEALJHr}{y zYWkaAU`nZqh&41#D88 zt9Nam!uh5NUfZI&7|nka{js=NH6SQhFL5{KlvVbm4^&2qtno5X$I&%riWifu%UcVH z`=&P3BDz$b<*?9Up@pMWq_w)dNrx8&>WGz=UY^DgOxG6K-Z1K7Jp;Xf{8p>|+NGy` z3`>HvqGXFySn4%;K|@Cz6r6ucd!zC-JO36VX_|&k7!2{#A#~j5uRc%y2FPx;`$f=B z^srQJ+2>A#m-d2XBGKGU_2tSAr|fDHx(9~9_&C`F0aHuvM84ATsJe8>IJy->NyLqyuLv_r*Y$E%%e9`X3SrvjN_C~S-Lt6ra*aV><>CJ@X{0(FCj>;2P z+f4iv=7zO!3%+~Wu+@;!)&Yn5Jc`4q(D7|b`d(=ebwfx#=BR9PI zyPPGoBIUywTVD30cS!(S{S6A@XcX!`RTf^AbtO@Dg-mDwAtY1Kl*W+AP9T&55)4S`z2f|K>V2kHx%uErvPw=PQ)YUq-%)o zo|aBWd4t+<)pudu?z41-8svMcpDrogL~ds+vuAu<&YxBzNgE2Rhe;R`CsV42L=*$T7J zSexpnAk<;-i+yql5-56`2ezMot*|^j5&9@}hgGd&XmtXFerwq#=gK%Fe?`0`({!|C zU}|l!7NZ8kkRlA2k13e@A@Y}3=3@SWGH!DYkSvYmEdKm$#Txg=tYV*giy`y?3`2FZ zO(C3{A4Hgwgi7%L%tB==CU{-ssw^{fwTQ%qJwBCRxTX@-Sh-F{nF%;s9AC`U4lyyD zsM>J#xu;Vom~XU}j^pqsc3B}xm<6N}P5;s9vZ0$P9@#W4fv$WdOb#@KSnI{gG0q?k zQz)52$FWHN(o|MH{ff@^RCYyfQS>3?{?ji4V^{w^JY`qpIY=2`!s`i4c;o*|cwxr6 zDyK5&jY3;yTO3QhX8Sg+5e_Ok*UIKR$ZLw)<30%1cVU}oTzHi$LM3)uyF)lukx+gE zRYHZOzbfG|cs1U&$>F`f-V0rD7cl|3juUK1#&ugr8{gOI<1(-st5_WyaUt!Eopnu9 z`7ff?Nq(I(%8xD~;E{V~h4r(Q6a42D2g8_teN{G1#W)OjVtZvk&9F5+%GNuT=v&ho zDeD9sRg3wJ;hm0IV|wlR@nzZI%J+-mgG|+ZG%78MWqa<{5o7#I5DSdsFk^g|e~C5` z=>sCqhEx0szlie{K^%qa-&p^Qwtk=nj0#bdqCdBXZ|vePee4ZdHOy`yh97oSKqOGu z^kPl+HXfJ^=xi;0H|o6r9#F6>e*?p|$+z$^X5oXi;4y}LM)`F_)Og{;;mKe0yX$7^ z46sq$k-*neGT+qCD%aExICo#jO2Hy!;FbVT{now%asYRA-}!lxLhJ2m;DHCe+|u%6gYfdX zXFvR~_#7e1FIY&kZRcZ7dB7|EH}f#rMJe*dOH^dz{|DQO83@Mv^B6L}i)iow7hEhP zlU-#jMM(`F;NY>QNZ7{vaeee>vWpJVIF)Y!kKhAi?EBaG`STbyi1{!N6#f);7A$Aoa?2YqOa`P_ld9I&8^A8~UZ$ts{VlTZM|P5yJ~DskQwN*fhv1Nkxq4160E?M=LuST$@L6>b|9`An=8TUexa z!Y*`3!Z}_Y(03i!n0$TAEicDpW>nj@i9WcRh}TYt!|wSDU~kA{3x~@jN)W>UFI$5+ zkYO-y%}!8d3(mC31ux$gl?o&Dz$Gr5iMXR;&;Aw9_UL#?CroYx5ob6-KYRBVSe$t_ zs#K*v&)(KaNgq(*#S)*2#*154ft1hHqjENGF`NRtGvk^?cznR{UaFtpLF!LfT`7*YhR;^E{_ zMnybiL#P9+p9vh0p@&e31*6q#JN@!@@SDD_fYM0-r!ONW-@mEnb;1%w`Hx;g`xgks ze7=8myC0U6C0Zz?x+@gVw{sG$OgbRz;ce2|aYUJinsMyTosZIB0dgW+BVmPyxJ1}0DdcY|tP3g(4^tLld=EV8_2;#{SJyw9El zA3I#9it%j?^maIlTt&O=FE6cwRj)_g%XK+-ms+g4H*4qFNqRLhrv%c@~VnW_88@OXiZ0L=zZkD*pk6P+1p1a7XqC4C_jF zV?gwASY7qdNuSc(>^C$r+z0dl7SJORKgC^zZNkxrvzG3fUu6(7viYZkS)VnzhW8?j zwcy=B#zM9i=o$i1!fUip-X0fpRnk<6>@g-cux3#59$H}a4yChP#T^RS%8$fnAJti& zjR}b}ze*;a6DXcI8+<1?^RUK$b6>q&41etXKed)rRt3m5H896w!c+4?nJ~NN-OT3@ zjvvTj}sHG~l`tf%_E1*ZFmNUFU z@^fDDOR-L85eBq9z)`(G+?zz)Zq3XL*^_X)9!AcIlzNx@Y+4`PmK#8b^TNM zQ7qK|UzHyYz_8lWum7L*91eG6{g73vUwb;np|-_h^49Z8eT!4mEz`g+lBhP;4G8Xc zZ-`8CG{pTvP7#+H1BZA(z}`uzR{3G)&P)R`-Mf_;#HTU6K+{<7tn$un~qLxK;H~~@*%^OnIa>$OA?8QPsLM} zI91LLG>ge?&b4cViOBUQH}4-~|At&|`q9TJ2-tDOqQ4`m>CHW3;j2cJ#|?5kTtSr< zXRJ4&s`##fET?_v2}z|=Lj|@pA)2!u;2PXmY}awlw)~D`!(gliX6Dyad+n{Zo3dg_LQNT>$O<1 z-*E8NsNB(p<|*Jys$^FoXUW!!2-+@?Bon`hqIheU1lHv;5s6RjdmE(K$h#F5uB?ug zE(cra^A93&4{)}xstlV#M5o)X&YNN!MyQxRD%~i{(%r^SO4HrY;8gFj!BfgTMnFo_ zxmE9`-jvIaq5|_Qw`M7M1q8{dNEFi@;E8{2 zFvp|X9VT81!~H$unzR_vq8@84@(3FIQm)eFBFgU1^qXb8=2b_vigUep+T~_BO2f5N z7uvJ3RRhw8ON>cNf6D#F_`4Zo%RDX?hMFPt9?t&Pois-0i*h6iDvr6|kmER}=}i%* zRub76bu$_{gpn5%r};HG+@-U0h>>P|5gi&UCy2{)N%)Rn@Y&6lt2+QzIW;yU;cEvv8n7b$YslKj`1EOHN1=L}lWPA(jv%M#|x| zqXL5%JfjSw@QIWIk_AI-AF==i&o^{5n0D*O?m!YjLyXC)d)>DhGLWAc-+cU@oU5(^$|(H&Hs}2$H^C$xgQxQGLsP!YPONTO)@1bxmkTnU{2voT-o0`1J^07)#4=D9b{0gqX(PgG2EZ0L+F_qkU`cnZAgN&mJ z?c4_{f>ZQQE2=dHgvO>%TxzGHw$8!M^{BUYRrvbLUDj&`8KT8(f_^wNS~Gw!D4bEv zZI@Ncz64$W?Yl#%9?0h6(>2}d-=4DENDV}{PDPQ?Z`v|62gm8)DR0^b$7I6aKKWFG z;oLfT^o>p*UhlLlhZ4YJ06Z6HAXuIx;Y?kk{&c_K3r$tMvvE0`7f5pai43d1kzusq z$q;;}I(MamS|~;{9p1;qtmD9TlQVge{$q3;i@NrZLInra^PPd6oY8akR+4 zeYrOhcI)XjVFfQ2Uza$t=~1{FwBplcHHxwCV9+kkSJE&8_$n@hW|VG|z278dh3G%i zLaGlrtwl7sx;d@14;OFvsw&Ib?e4R*c=;C3`ILU+5>NIR?GjBdbzc!Pw;s;cYdX`< z@czOR!v=8$Yd)r?1`&Q??ENumcbarU)5kDIjZKmhTd4ETER*6>4$#QIi^z4_TfzK% z`$^fc5L~BI0hbVX5X%F8`P$ChkXF099JU>OySo;MIJRAvzVpwe?LOi*4lELM7md=9Qr7$|m9f(++-zNhdj)mY~a?;ub{-#1=oXr>ODWZPg zxEl<%^Z$ekVUe?Tmk|wp7VprQWMoKUf}NY{Vc-$WvDp=L7ZL_^Y}0TZxd9EYt}1g^ z$y0BCnd!p9LZ)9+6ru|g%5N6vi9_x4&zGZ%ISp!VASGJm>adU}qs5)%0EUgZd_bg4 zjo9$9BVz%>W2MGiR1FS%XlYTz2C=J80~t}*PPQuL#%xVq2gO)ycxn=3*rH=`NMHKw zoXi-kC9f{S5sy}p;GFVYHq9*^i8}JTT2zLoAPxcLLo^-k3bO!^B@5N*z(VYYWxe-j zC2MYh$XHb1ihS1H+!bQV28|uV%Fv=L*^V33GGwQqOJLV*;+axP9W#AE-Fx1+;&@)U zTDd>$On<4`B%>|}v~PmmmhLaN`cuJQy@^8_0c2PsNL+lleheyFcl?EpRL;s_OC|;R z4`hK&e0anHPoKt1p%)t|Xz9O%g$43vsPgLv?s@>1$G62m3sa?{R79_FSEm8aPL&Db zBGie+ALtBdhb<5mPS-DYTh$_(pPhW2qqmbiRb^&9ecFzO8y@3GKNlK|pU}*)zy^~c z9`_bWi-&U*N)LpSA;Rm^%+0_{#)W(!eMpO65xf|8kVY*pPwDMbt}FaIhW#a3rong@ zZ71Zc?q$O&#uh9JEr*72g$RepJ_LkqQ&rvk=r=ICCD%$dm3pY^R{%pik}n6Y<+*)1Dw|@ zHH8_1nCuR9LPIT7<4%?Paf5ou@O~E)%J*Yg;BtE(A$a`-jjPzCK#wzq=R5e?G_ni? zpQW=s#I`h9?B9pfht!&j0dGT}OrnHYi1dZvlVf3IG#PKaGEKY@l6Lq(t~65kK`Bjq z0Z0fLZ>K)S*zProv=Cdd(q#3PYN}nKMQTun+Mt<$JVeI@?oc9brp>rBEBIKIA9t=G zg+EE!R&^rQHJIoD>J@oQ-lRS`-{EcppA?IR&_QFc;fb z8gcO?L+jFdL?qanAE`5RZ<-|X7MPb|-UWm|cP@|X$WgK^DH)};m{PCjZ7_3#miNw{ zX728J-$;~F-jy4sE?GCq3ON?%Q$TSJR?vl&*hYTnU4`DCNL_om1NZZ-fAj&Ko^flc zRpOQfMd$89EiSk2ZyP7aYYuWUGe+p$RMU{IxL*oN5Kb65w!Z=m zSxW0#FuGe63qLI54U-|iD&;KYzSR8w090v=Z z7dfpe*jky8Ti;`VQF!tBr{pB$>>Ut+h zu;$gZt7fmZr}}fEMZzsZ?D*qsg|)F)=|6BuPKb1NjXFZb_p9ly((}X2)x+{q^r(yAmCSw zGRhty3w%cPA(tIRHA6!k-cv}_VUIYAk1XFH>Lr!%!6B(~iRNeMc{EBf)+R{rf=}-K z_Ii91->#NwKx_`!5s(JtG<>q~Ls!IXl1w`>1!BZXEN}B4GGXd|Y(dT)hpTl~_u)|I zJ&zyk_|dgzb91#vIxh%yPe?lpGB24+3D~A|0>iJB^&Kizjgh7LH2>F_TI&61F(J41!>`IErO@QjI3G?h)AX#!>d)+B27U6Fu7)4*5@zo zXo)d+Eo(t{$GGNzwjVA97}MLT?HVqrBbesyr?1<`+4@3~Nx%)_Kwz@2ancz&uk`65 zh^FZyx-#G1=xswB&>VYyT=5QhHETB0`u{C8kw*7xF(UPUJVzY+)E5d zZ5u!|52NRqbA-+CT4A?`Z>J?Il7}4|9MRGE$oBp!2#J#uq>{UB9lI?FJarJ?NxCrt z1Ti$~clc}pQFBC0qOf4mcsdnG-En9Tt^cK;JJYU2`*-=^JzJRH)t}Kgqmf_G?U0YD z&5J+!5X}3ueomzr3N!<^ol{aSxXvtzp5JH?^jl!s;pna0NOvZ%g31^C`0+IBPcw$4 z-MCfm?vNU_#;3rew8-P`gCn=i*_J;jQ)vCkG6$P45m7MQz_SWEomRs(MJ9{+E?dop zpGLXhC84dq+|5zmf zb_mBvVX)IAD|_14ce_oSwemA($E?7Ygv|j2!h(vu5mEEQEu}hbCxd8 z4PV+c0oeFF-D76yc-gOiSzqFD$r?FEdb=BsN5B)w$q}*k`~b{^1x~^KT5qYI349lM zY>1{YJU5NO;Hxt;w2cG&n#ohT&{6e-cIp<0mBH9Ke`4995^>kqf~cof3JuC1aUeoL z#sF2ttdZ^6A3a;klwp}`dBB(aB3xs#=rpl87h07Z-D0J~nn$Fyr&`;-8oV>4=bZB* z+)CJ!MFqdDC43QYgY1Hd;n2GPAF4uY@z}y({w`Hif@QFnHPS6#Is!Lu7?#;YpM0rN zVm9nM+CdE74`CqjCb|AgybA}&A1|48khc|s6WYzI#`x}>(XxcwB5{})JF_DqH=_1S(MQ~_dC>YsA<-XQ!`uy&-|H? zqf#xyK-nqr%`V8{=<27D__u1h1EN%vf(Tqm+ySXp6Vt_Y$xVrQ3;mt`lvKKn$S7s} z#YEIW81`5pyA_w3s4ORUbXyVJ>e!AQ7`tTDa>kQS6}C7v?~kq&$-?!hus2%Bg7O)i zkZq9z!6g&Bocpe9umJMN_71fbTHdWaH-1${tc&yvHa>zpY}tXO5di%G6@DJqn=27t zTd32r?NO@eq{;r7+~m(ZC`(HG>T6TJ-s03g+|-vKXYBUku#mRhd~1$m=85Po1KIFv z>u8)x?q1;ItNM*p>19ck>qh6(!iiAGV0Rp^3I|I~#)Z{-R=>Yu7AgGz|LYraSK$^B za^+&o3#92xo4s9Ym6ANfR)zqU#e_5EHV#!`o%T{MUlo=i3USQsg!(1sn^C8y2r?!& zIsMFM@=e|+$$GH1zq7AlcRN)StvC!f|4zB)e}j_{BQ5l@cbtgyOp!gz9u$#46(X7S zeLZ1EaUg%$Kmo#6NGf>B2FgJQ3Ae;2+b|$}iM#iWBJKj=E5M5KT-Pdg*ZRlDB|`ma z;!T!S-0o+|1@D5$(on)T+|N~)>LrUdrjFBr2+7YLETJa)^h_CCcS!mbmRm?hqu+fi zlC8^Bx9dc0?w#&WXo&ia_42wy$CvzKNW&%b4RVRhR}!IV@y(r4lD+3aB_E{_4Y937 zH3#@+E?ye<8^mhQK`lnE#L!$ZjP>Uh5dB8oL0 z$_-DpMtZy+flvxFkYQl5#eWnKgB^PhFxn{=v4=^xI|ppoA9TVz@cAA?w(b5)K&7E? zwf>~oYQP)U@+ZYsJ7^*6QT^mo0Zg&AfGM`!;Wf&QR#befa(q*5aA&xe!hqWNiuJ4Q zJWGM64z`ev6TDo}owbZY!Zqk6O67ZhrRy z)caXx&}KMBZnXud)~QxCDamhas@@mHbZqVar9GYJnxFa8sD)eo8Cqxy$R}*j;52NH zdnqRvHEhQmwc-w&K|&Z>bXn>*UicvhJ}y0p1KOFtY8v;H^DYulBwdn!TOEB;{#R7e zb~7Sv!t+9c-dmB1IuUr1+*_$e1@5&m8`$UJdj1s#0Ka@2%fxa0Ctrv(U8&p`DnWO+ zERbycBQx0iCo^b&Pfk73l;LOb?ZFg=ngPls){vc`S=buW5uA}M^S^fiZUmyB%A6H}8g1Ae)X>qV<^E z74}bpSb?}Ftw(ByMPJ9e$5{kYJ-+v^O)(0O3iK42*Y9r)sn8)>D}{LIDUS{yJtfyD z!xH7i-d)-j!mRc(qQ^h*(Urr{aLv zhAC((glvfS^BeDcZ^N~0qooA{H$68gBxK?vj|0M>{`k=$Ndz2`hn1W50?nQaX*bki zZ>siN#i}$ZQF&d|0jz4k%mJoEwbQ`MfZb_O5oF%nkj%%KM7Ca(@WQ3oOYqPLF!jsh z=8Yw}+sg6Nj|6E*52_NF1?3GFjDdSiWR5TO8%(AdInr)n9-2*;xgt?#N=I-NTVo!p zGK}Y##&kG$Tc#<7tSo`;hro zE6d&ckc%62W=$IQ8fhJwMH=0|Bom7OoR*^TU-QFhp2=u<=khkto26(tT(0eJAspmS zBToLmz&FQB8fk40tMQIfk=SY3gh}4+uQtDcCr_JL5_sRt^qHhsLbJE{hCOHj7sQF| zI!`$9U+i7={C~sVe2W1AC&C@h0<-pK{B6Heckl4jpx{XvJn_y1t4ZS9-FX#rirp{s zwbARC?C)fIA2&)A*X?1~iE!B}FLBU*i9SJdF&L4tb1@VJDle$A!tv40Qm0ZxhRQFf z2#x`v>vf);r!mU6NXsdNu zRJ7j-!NSjRk~Jy5bIq|-d9JclRevhBLbB!0^G8(YtobI&T;xkbU!74OqXD}7i03X3 z*1P}ojiugm-bDcRQS$WR1deNnXo6E@M5}J{9{ie^IpfHd(lu{j{?p<{>Io=pku)&! zcsB|#pTuDlQ;b95bc(|fTxxn`|$$)+|5bdI-oj>D-_ zH^+mc@S3+f3yka*4{9w2Rg)17I9?#vzIZMK$GV?$jR`{Ps!A9C;R{A`qs85dSiLB+6AmAK|#sN_q2*8xC2tp9&?D zMj~{rdiD{aMak&?9l$^kSJX!Gg59t z+C12=y8SzdO32&PmRoE_S?lz#k{3wR#4%zXDA9PEM9AH7wkD>vBPX%n#5S5p za|8*gVJGpw{UUM224yNJ=-uy)^}AnAG*2F89x+g=2Lj7lBWGo~P6Ecmh1SCkvw{;r z>cvH`hIAep(|3sMa7mCwlm^F@H_;$O8#sV|MSOxeMqC6u#>> zkHHI@peGu3y$|~A9N4-v6A4(T^>vRZjTgNrjl(5;FSX?}mM#f=)t3n(3%xU0J=JP8hLXZ6K^6JBvHGPStbAySm(*3ydWjH@&=#qscM| zP_BXDh#v{{fG#ZW^!p?wRv2^*{q~DHbiAsNiL-H%k{D^l8$qja5_N@u#vy(EICgKW z>K44DnujlRPssVCJFX}ZPv3)1p_eTQp)Cal%}t@2+9DmZ*Kl)Mu(q|;ih0)^$W1Y7 zfy1@S*EJ@s##k)JTg{K8j7tniW0OnRHg>exgGojFZ^C=4iVjdl#xDe&54?=9(wcB6 z&S0?+;7&=2Z{(a0QhOqEb3QwaTdFGK$lCqLjSn4kvXA~=h-89Dj*PKo4(3vkQLcl5 zEjc66BF^Dv1_k6nTmXZP14MBt>Hjio3I3sSqYGz@>FJI;YAIOiZH4iZQ8!>QsXK$$ ze#}k08~=9m>p=&tAL(`!cBB{g2U4D9@{&&IO*iE&RIEaYBRg{YS>&&wjW&a>%riJ7 z6}jw;U@_-kQDV->{19T!9{ZDDpFc7k3#KD&daJ+cnjh3A0wAN0YzPgyaMbB&n^G* z6rf^{X0yiPFr#EKfO1~*k2Hf?nNx2@%uV(hlXLOI|6dhm3?b9lj?CSc-#37I>0hy* zT>V!f179)+zq#j_k_%ybR?}UJ&0ZrCqQn=B>LwNRRM!Tt?SyO_g)b3px^Me?B3I|P1~it= z+y4(+Zvhn70&I(h5HwhD3GVLhHn=+kcX#*T!QI{6A-KD{ySuyn$;mnQzx&^>qNdo? zp4mgqp6=Cat?ni>yRGs|T%zid#?sT{EFT_*bd|m;+~HdkC>_f?^m^nE0cT0CL5QG# zm^l9p@Mtm!cnXa0El5uZ1#?c&jur7aEoygqcT&8DRQ#7P2W?@+OBI8nU=z3(6(+WT z^Y69D&-zi$CP2mqm2a7wds*}i6skQsLg0UdMGk5MYL1OnVN_jKu`r++pmxG$hM^v8 zEDQ>+yThbl-lK;_w(>V}f9)E9Hp2^8$B`EfwqGxo$JuK#1h(IQRVBzkMp-^^4L_5f3YPyC|rfg0wqlmB9mNeV>)ji(#2m{3dyxGktWz4 zmpSKQ6D!2N112~HD8T(L4Iw}C9K?=4>Zq; z%lR(qlkYXNLku?a@<$izwAlW?)p3>JVZ?)j{c|tv4t0PC@0ayDRKzekUPxF<$73Gt zT~wC^Uk7Kbqz^km3)7~*WLTBDAmcjYtwr1;z|3t-b9Ko@qT=*3`s(u5tVLU5U=&-r znXsmlanBh1f?=aFc5t#4eSn%EGPUx!3G3$MM3CT6^uuGg?oaFC&m<60%&V>oNd~#O z08(+F4*=`mco(_(4F36;{r?hq<-V`bmCp0YAqX9$@-Nit|- zAV2^2sF)18@Ka!p4UnG)P7T|PHzs#6+8}e;ukzz{DQHDS3D}T*9D^$(d!$8fkHx5; zDKR9J*>wmtT>rMT;_HlqO?&;_^c7e!h4VrMFuk+ei0zPuXEMG2VtW6KKK~}tPzn-d7Q?_UCJ`gcO946(N}!5K@=_G@Qjj~N%(lS@=X!y9 z;g5yJSjG5*rx^3|H#>UFm*k`@vaUFD^@FC;u%gBx`k4B=xSLd2=p1vwOv6ejK@ zR6|%m7>#}P4SeYv?{Dnt{W9>(t8jUW@664?z)CS+(dJ*By1zU`3CR~?`3Z@w`uH#U z?=Ok}5o}oLyVj9j|BC6s%BIh_XfjuQv~0Hfo`(Cys(imo7nmw{aylZWJ%GIe0ELw% zBa@4G^f7%n3bY|U?y~eT?63K##P_Hs2NUauS%2dOA@=wlokhSG)M0u=SN?(UCb<+d zgh`{jhMSEthtvN;;va7l6FdA6O8%YaV&&t)b( zJ3+NFa>&JgPfh+p%Dx6$N;q0%Gpkzyo~GaPpWQ3S+{)+fxp(h^q8;1;l*`Zo_y84P zm#R8s`PVr!c!>lM45QUzK z|C?10z;%Y&EoHF{bKs_A3a?oHVf+{x}szfldX3eISi8`omzK zfKf%*2W1;H`PHa%r~ zQ;vLUzZJ|?3kKrkSayLRA8&#aWuLk@;l%q1k#_GxqQ3>PK55rr^^m8S0glOm%zkgx z-$23CV}$*{UK?x<%nx_K{9yiXe!$&XRyg(j!{WdmY~N!ox$Dmb{!#1vo^T2NM_{47 z%-c#}1V%rgKTUoYBMi>ACRYcJ-$`4^hs6rV33s`tAuD`A3di2F8=wlVPC14uUK>sa z7&Ih$6Tvfo<4zlyAJO@`73K$0)-8YckE{~<$O8ePDA)B=E$4ccdw&(bQ1J8SKVii8 zus8gOwX@F5*A^R6BsbRoehdi3{=c%ybYstnv{fB;kll8hrFpHDGxLAw99b-7%F}lE{I!456%CW5;7Iu*xE-Fd zL+7NE+a!%E=M)H%c^x56qs02RU}?;ReAZWyX`_dAFOCRciQ@s3QmlD6BJ_Z`amQ(h z^Yhe@>J8rr6t0Xz*5p0AMPjSxAz#ScS6@nZVk1RNGlZxz?|}A3Xr91Tco4? zsFM_%_X${rZZa4?)tg$P!BvB8pVI$_p7A_|+5 ze>D_)MDb!=-0@(f0X~?5nJR=vLr@HQXk*tNYf{vfFYcYwf;#Uf!Vf0!PcHMD92I^~ zcsY?+_PKRITT}JBxqw7=KkGd6q5naqkM^tskFAHD+6N@}RoD4Jq1aA6PhV4tz3D*J zFO^$wh$SPa>jTxrpz5)i@SM|G(Ed_5J%m@%{a@(9Nl4U1AaaPXZkx4?wFc*_plTdT}IS6Wo>x)pDD#*-S2Pow&Ie5N@oN#;K+6J%D=%aV)Oew8Nfb&4o& zGTWZzFn0(-JgAPeH1Dl}-ALHp@_w_JwLkZuA-vn91Vc2qbWh+;#LI{t*a1f;#$2&M zdNii*)vG$uD-JUv#!qXat%d)IrJxzyF&I~tIZnV}Wk%Zm7oQ9~I{j1ax{U*?UC%I1 z7TYW1HcGL%Rt12_Tx+asQOd*j--=_L;CyqfKyT)LkUX>XcNnFch=^l_l6}p}EG@L5 zGQ#f1pIrX@S?D{94w{MxL_cB(7?kiA&~s9RXXv0<->U$lk3kKkWm>I$KMg=@;K^oH z;(>cEQlK23g5VhigV{ zb*vj;{X3yzHEPC&5wP9(`~$m%xThl$wFSwuf9JRtz6Er1O2#*R)zmP%p%8$TLIxWy z`Y_Z0TF&IT@C)20BQ%ff@Ke#Z ztVlj(UDy(p{V*ay8fuRY*{$;15Q<6V5D^7+D^bkMboXNrm%SVs!1WN&Rs1hccv%G{ zTUNPk(U8ZlCe(C|h_=&0Nk)OI)Ns%39=eh}L*Zjp^hjc~xJFx$m*3FXW23Heh@zxX zeqwraNi~*d8*w22U7tm4?RR%hABZ;ht6B0kTt%Y)=O(lvU`nrv$r%*x&4VrO`+Y2G z-w|mSR?nA>-@Rs9(*in^W7Hg%y!W7)LJNPvij&i75ppnFsK*QEKRi|7T%qVucoD% zNBJm>_cR{*ffaDd$Y`t$(`!|;KbEIFWGPMShi{xB>HMq|9@%yr>3og8=#6?NhekU@ zG9b{ax`fM%>NkD=?W+t5GVzUfbNI54R+RwIC=#lzDwGovaaBOxaQx`!6!nRpmmQk0 zW-0E=?;fF>$0f>RCo?=4=0^Dlig1b$t{74NnsE#Lnn4S616DChE!^9^EhseGCf!A4QW`q!9*7Iz^Dcb< z{l|le_S8giZI99!l{xYi;6($Zc-nY&RkL*Fa{>51U99qSrT-dCY^}}`t3xz^cg7X) z&d~Vp&e)mPCztG~PG!57BjfZGl7b$XjNkWV()C09{8x*q?3`hXB4P7j`7a-go%1)Z+B zDp%W~s0>^%HB?G>&AnJ1o+{Q_aDAS5GC=-x(b>O(fG^@GV!HO1bfkg*!2IF1%hyS6QSNBK{khp+g=nadwm!69mnXNFHvqmm=`zli+hSTG%b2caRP~NCy#e>igOZ zj6r$IDqc1H6Qy}Cc-}YhePW(;SphU*e=zO*FSn9*!^O)9 znQPw6F{EXr-Y;_jTD_ZCL%8SviTHx03B;zaK?7e2=hs41==|06dL*DZMsb(N%&c^a z9mJxX-VK2X+~Vs+*Ugje`Wv8{zC$o0z{wbF45urugZD;Ulx)(26hHm(Naq;m4U++V zBUw2eA%$>$+bQb@=-E$<>bPK`k3XKvD^NZLtk|XBI{pSM(g5OG`sDDL=s}BDNWam3 z+;t0&O#4`Q;@ILnLe~1IsjB~sj?iAIocg+qcGfBubQ4apNnguP01B};izsJp@eEER zWX8(WfTce3Uq;|n(xq-VL~TVK@5d9~dM#VJ{$ZEr^vVzQXUt5o?7v;YbejSgrpNGF zslCjvw_R$fXIg}~T|G#6L9`0{5;Tm*jIdb?G)yZ?q`HsgatV1J0f@@~<5p!eS~t+g z(|c&VA$8JQ`Hy-k(`5!$7<$*xo6wIv|3@ zkz{nI=(E^VXh_AX*os$wCkt1tkWSNyChH&;O?6+$d~gDr{+05QYya9XTPpr*{$_-k zHKRTfCWHVMhy6c8HDjY_2Ry7Q%02v^DB&Vb!*_wO)hD0LdGL}lZbS71e%wEd5ZG>-2{H!jKESl( zOek$-WgPg~!N~s=eYg8t0qujY2Ll-9G%$3;7$(@Lu&*b1O>1hXtl(TEL5F;sjW}V3 zm}Lr7~ZK9EML_`qxy?$37%upHdzcIux()|+Fv00 zJFsnm2twFSmPkZ6`a7^~VQ331R}{`Wi0?X@-qXzKuAF0b3ud5830jYLqf+X6KBB7+fr5)6o@aFP%-fnh&NFj zM2B4eElZ4nPEi+~Er5Ypf~+qXZ)qdyBGv1!ytVLISG@Fp(I$$Nru@rxT^^ZMrJsmf zQB?+lG72ZQAY7YIgHjx=BDbW8^NTauVLI^!G9F!H*ri|Xc=JSf-41$g{Hj;);f?wy zCR{B0?!S!r?`O>%H*;eo?!hiV$7JwInm-gI7FsHM5r6Eia%nY{4m;R%OyP1H@>yp; z71X%J2!$)9&~9DQzSRd-_xHSy6cQJ`pLFoPtZ_-%t5x!8*PAsV+qo*8?8Bq7XpT@P z@k)AoI*sjd(i|(_jWK2~<|wi5FJW)g6*+TxzrQ{$XnP&Kzq~%(?0mdmouEy8+}>TZ zKVHjdd)^fuct1a%9CWz951?s#KJ{Ic958z7SKam7y|oGP#fGx-A&K6xHCrYIaeV}2OxPgfQ(>SJ@FO&5I4jo z%{+A4Tve~9J}f03H0~L4Sqp6dIqP(;T<7t=?^~GA@?aSvof9=I6uYd|b%#By;CNz< zFI<4E$Ld!lHJ&J~aFWrya@vj95qY01!FuQ@r@JqF%hU=XN3S<`A6qf?*ilBYTWb6f z>HShxB3T{?`_Z_yhh3TdWZ^Bi+V*-(hR}mSr(M#pG59w5$FM5R^<3~grRW3(=doSt zos8a{W!16obSHIZu?suVzfqVu5b}C|DHHj0;g|SUzVXAaVpea0sO^GdJ4d9_!}Ik} z-;2X(#j9(@s;>jxxLT_#@Ip2Hn9u9wc|cpcmHWB&Vvs#+3+eTF>SI9^V)G6zMZSqs~* ztr{WfU*}8m_k5dep>{a^f!irIMxi-L=Oe)V>dzT$as!c()prHNp{IYtD_lCgn=dWTr1$x;Iuscic<-V2QTA5g|sS`&sXnQPxJEV^Jfy~(F(Qu?p(s9=>E<@jm3=y4qUt@9^mr|9 z#H?FYmBZR>)~W`M5-*@wwbHoKl}}ZJ!wy1es3(Z_FI#EHP!SO|(t#`Z4S|A{1n(H; z0rP{E?TfoLL!S*K+_rxpIg@>cz2md0l~HmlTlok|BJ=C*K@Mnu^G|l9A&lw|^G!^q zKR(qcW5TVrE)Q(|9**@WoEs(?t&~W*If5&a8)f|Hr);JF6QB!j$OL{kd=C$2Q3mSHSfLSw|LM-k zl(1pWKd}L^Ps=aNC(Ski$y|69qK%{Uu_MjJilTJGX%ET# zvOrOP-r}0(0(TX86Hb?+4pu)WACo~0TPePGzU65#pQGQSvlj!T2#xKu`;UGIeoMXy zs;(P=trl?Eg0@O0~6_153`972-?x3us23LBTozGEG0&}1gPu8sn zr6(DGK3D>st~OLD)bz7-7DcGVpK{r=?uBP=E$DpNXJj99c*r9-SoM&bKoI)T#DGrO z;y0M`gSuZ`u4tIw00P`23P@7f&P${E?`MP4G$ZZVd+L!gg8;`Iw@1+VX}a=EN7J(@KrihNfcr5=uM$ z35BEKV{Wn2*51*|FF%5`Dp-X2qrbI|I() z#cLM@ik)%2mXK_gr3CaJbI}k&Co>0qI32wybatbYgTI%VKcS;Z9LwmqNaLBk zmRAySvY;Xef{O*C|Lg-D=iq?R&6)al2Sx;lUp`2LOE$}hMJfp+X^Qy_*frOVRK^y` zl1Z#7C~&{lE~Xg+M3QmVkb=)NETbtPnaWSHiJs)D9%_HSmsyIbb{ekSBnXFfIa@4! z%J!33Xy$i}ME?x)c`5uNWP7Xb$!a%a1|lAL8Yr$cmNe*yMyNspUa%wLWuMH;68*q6 z*7WRxG^!!vo*Av;(VC0>wjJ_|^nzu3B<(1tt6M*9dTF8;(B4@}$W{1M& z$f13P!WYOx7spq779kirc!m~b1{~cf{BuJ6A?4m2}3X#1~_TwkhB!q!DpJyi1OJOKQb_STf1%GfkNEd3 z61<#X6qy3i&wWw*ii6&X9`LEybXp5-=B}_W{(<0LC;aolyI!^ipl)9)1bRJ8=#xSG zP&MPFOJNsLZiT^?(hn#_Gmhr|?!W+6%Eu3AOKxim=2bW63*azrJvpBaj3#Ue&^4sD zVtTWQ(i7PXAA0D$E%rBj`3N)vWx^dW0`I)gJ&{d@*;?enRfB6J8}5FYgV!ia32E|| zix+0^V5-iR`wG0&4TG%Vp6>-D7a+a8UEPuX`j(c8By)2O;xhU6MVO<1CQb(Ts{QcV zh?uIbdy!ofX=J%5pbuK(|-y#w^Gq)k9-vd-|(j+F+fFDWQd}~5@^J%U7DWQ z5F952uEX;A+q!`xHD0?#<3g>jdtnr)Nv>}k*h+iEL2Ff*()6uf*6p4BEI-LyTBBZQ zkw8usaMuj340O;k3x-caxZIqL26Zx`RJcI4)Os?negS1r=nPt8BAq{tkCbXx1g?q|ioZ!$oy$>5g;A~YhF@a#|-^T64rL%Vy+|EUv?nY#S zs|BT2>_Kq*4A(GKqF=5~@Jav0<4amD%tCNpmycnJM$&~nkRI*PGRxX?-m8*JIfgZ9 zhw-P=3oh|RrIH5;rJl~&o9~8EIyL6RRkF_1YJ_<|RhdF7Z+2x)V~P|(L!YTpT4;T1 zQ4rqf-0mHAvqbBny^B;3CCzHdeka=~df$z&o9u3$%zt3tRi;i9ppgO0Lg1~LM$t7d zzW-8e?mM~++Fn?ig()lH-{i>MN^9A9)N13si0-FWm=w@-*hUc3{w&5jmRz*HgHJDC z!x3Ky!&x27nwj)@0>0nwh0d+NBlAxk(mRF75yV+uu@W20_ON=sek*@h*sIX-=x%3) z^ETDT%nWP*d&t$EP-PD8-cbCyo^m7utUsm>Yd&gBf0cebUrdx7ADbixbsZ*_oUyiO zVCm!eqn>|WWSxsFsG+oxUtxOkPL}=9jq~`o{p;sH?O)PS<^QyQ3ALKTVq_cYw1_$=W2x&K|ynTEX4s>)ps_6 z@y1Y&qH1>&e06sQ8Qq3n6-u?2F~r3gxk0VFz$U&|7f7C8g|y4-Wl4nBmX8dC(mRgp zi$Eui3uolDi@yud^V0=rcZUn@dMk&F8vF4z#%t~~7$x@HsLu3axllQn`P}sN9@TuJ zpej%y94o7`*E=(@p;4KJbHZ3W_Ibr7{&s#qNhHkPmd8$N@R@}dM}(Z=D_-TE?Wn{S?A zgf097o+rc>(nqf7@z(wiux#0x#E+kJkt7|Tm6NSVLuJmUa$q;d$@4y|0jq9RRs?IK zS-FUqw_zT*X~sB`y;EfrJieUTx^@gX1T)%&{E(#wdXp^;l2z;fFh;5X6SRpZ zZIVQ-ZsU{2laQ)LLMwe@*JlXJ`_^>Gx0S9l&hG*^{lNSUK31mgXYh6FK_YiUS9tP~(- z6s&~fFva*^j!ZMHN^o7>Y!IY;%o*Z{&BX-sEduI;&n(;6+mC&^YMg$SjaFcyBW9EQ zxoFr2`h@++R+-@XIXh`iQmm~uS+)T3-THZ+TAT=$QQXS-3|+*a>uipaaiQo>0lR;zIXfokJ*)bT24Bu6SjFD~g{I;esgpqBzR&Tg-xATNW zW<#8uL==%t*0g(6S;l)Wa&%A~dRpL8nqqV!(5zRp`t=};^;5&fEe0HQ#mN>STPlaD zMnX%`O~Ro}B9>Zz*gUE7L8<`=%yhB$yYqjh9)0e#P_tiEAKfw^E80%8Dw_KvX51fhce7-A~~}eEILXVM!hN&ATX9;03+5TU0@mOl1aNJvhnDf zBC>gX3S@OB#$~XLRY6qSf#N`Il+BksNb+!hpFz;(#rW8IIsL>)U;HJdhsIS)%=nfs zMuKgJl(o%((QOv@)?$e6*KTWpICIo)d)~0(g7~^heyNrI$aD;F>uG;DwM;UWMwgB~ za!XHQL9w&GMCE}tafw?Hp``p{zjDdFVF!+-54(rpbTcW2em{V7ZNa2a1oP}x4QG%s z_j@~ZhYLB1NU6gw4}o;LIf9rE#4<;s4_KMvR8lpm{y;d#;+nCOA*Z(Ra+aZ6VBVAk~m>Auzuc9tuALaFRm?+wSHecmjaS-AL)UND-Ld=T%~`vAzc5 z`wW1ok^RUeA zV40IaM;Rw~$@z`~lbLcQ6Zi{O(PJN%zu22^r;wzmnFcA>2}WX_P3Dasviaoo$wY)n z2uv`a6d)-6VrSJoRBdC#K*S|a{E}gXB@H&P;;#^$`STXhvQx%oj=twSbzD|KI$^hV z%d}F_Xvz6z{VMK3TH&lIgjTf0<+-a8oixT1x=Ua0G^T)+ew+rDv+H*n1Jt2Q%a{2C zp=cNR!Fq2}7}B2ebcQAN`*Z)P%r5eH?2yDlTSK9pJ(029fulH~V}t%2c!?}Xi-@YOd-^>u z#LyDR!BwV#QjqG@+ZaDAxdGu0d8Kf63zL-~#{Pn_7W7 z-(T}gB+0>&4O%N|d6hF`Peoicqu_d?LpoZc!q{rCIvMvz+P(ZJb0H8bT11nP0eizh zOPd1nQ?da^psi0%`+}Rv&?;R1YfJ5zRzE?K$v1nfQjpB=#nQ3N+d}F%u5O~Mc{u&@-L5o20zZ+I@EA1eoJka2)52SrVr|>u zQSj=-!VFw_4$mfi%4U4c)}wMg^Feecf!rjUhQl^EkJdLYb6-;N;wlQATrGWAAuwIF zH&sT`_W(k_$rGJ>XG5m7LC<~L1S-8JU3uYbNG#3W%Guhj_*r4QSo@Wmoi+0Pa62W% znxgb&s?xX&Q)sKF<8}cPkUH|-Q-D$N52ub@AK7Y3bAobMDmLFz;&=n`r~e*x6t|#* zr)B>d8_luwc|Td!V(K36tiDRxnqlJnu>iJp=jrBPqT~Hq;$h=pA`|!Hp$|x(U(JPX zcwX&gwm%=s{2|#FCcGbBBmc1Myl)k5?>r<~tO+L@+_YW`J&`Y>%X4#c#;r&lKb>@u zQ7*o$sz>#FBpaXbrWy;p>Av(Co8zZimn70;cBY09dO&=|#}4|i08O~)roJdILK;CA zLMdNHy`4kct#$N@wqXs!M6coNzu;(d?p2|?+# zz3Sp1-L%x{z(wRYXsW2x62QrE!F6z}9bfGY>YjVcaaOheRV0_x0!lEbcBxcIRvu;LUzUi~_;9jIe@xAx^JL>T|xPDR&A|s1|*>^drVGgkBW%AdJ3&C*N zsaz-(=9x-UlC^7zU;5Z9bU0Q$!VjU^+XA47Rs|$lUSpU@(tB=;5mt@xFidZ5?#sj? zuV-(iZ|XVCr2h0OL$OM1QdVg1cv-Lm24|R-ovOL8E|VspfKP~kgv_%Y@LoHVHcU2G zM@sy&P~MzC?3>Z8`Hy41c1R~I-rQOAFtyb(;x$k6;>Ez7RKL6@Cx)E2&m8>%vOfaz z8u@a2{NN%PIk`mLQs0Q{K;VI|Zy&W@wGsP7d?noOMr9$CS2`G$HzE9`L17F`eeImr zEa`?lfc0Q)otn(ZxiABqeOmYKUB0?4(?aVALb+>19=?L&;F1DedmUeS%sxu#BD+&^ zJ6ky)*FtHYXq?W|inT+4BoJN0$}PCsa8flP%I91w!Sv4S-Ah1;Qgk^v#Qx4}4oR11 z$$A3X~K>--@d;@y57w70V!gI!~@!iR2w@&mnL** z>7^{9{zhj*rq`AkI8u6ui(k5wk1&;eX>?-LD1&N$HTlJ#>p#$`Np0;?LfN zBn-k&lnTi+eIdyLG1-J_;!rWw1UOh0ajV#xyN!%nAT8P*%-(U3Ps4o2kC*bt)mG&g%1gc0o!!}zz33`zN4k#cMnKeSLlU=Qkq56G8+K#Hu(RkVds1#gZsY7C zZKajWk~E}(QuUz#)%Q_ur0-};n5viU^}LkcZAfLFu=;ADRo6=vB9KE!o?_tgWJelT(?6cDXz4Tem16u%FA1jA6XC6-`Kpnrq{qGXH94w>?y zm8y)n&K*T>6;i`QMp`wj3{?~Eqz*NKUb>nC34j~m)d@AsFDj{zCpj}_X=jt`lu zC*BXi`_#Kf?~m6v@6LyhkS|ZKHyy9MY$d4ETI8P0UVZ!^VL{XaR24QQnKF0;IDTB< z^m7#wJbX#?V5)F>dRjBBT<;a-BELdphE)B#KBRv4G+8w*zEaB*({26O8QU<#Vn5sA zY7*FIT#4kVsp%5Dw8j6~6POCnTF@EAYZMm3kGl^;4XjGBZ&+Wo8QB0pmW$T_fP_IR z*p_X;FM&?gwNW9ywCwX?Pm#P(7&-TNJ(^)=)U}!3q3Nig@WIa@=;g-g!ES-Q z_eH^rM}eeh#^wB~`1WT_-;N&Jb@z4$WU{3CjLA4R8mY*itB6$_A-V%a9fzu?YP3gd z2stt1AkZdsrrR1#Wb{i8Sh}oJPg^DLmPk7A#vLzX(M z?5-95u6=!;Gp?}MXLA{-Cj3>m6!)~7QJGA&7K|1{`6;m` z*mk6`ks@e8wcWnL<>4CDL&2SGb&wo2?1@ir=tbfXX0gld9lB_QR?Sy4fk#d_hH5JF>-+K4u5>I@CjQZ zI2%6HV;nH3f|vM5uk90gpR-hSe5+~^5-fL+MNi);g2QbAzg3>Stc~e5H~3XOr5~0^ z(@Ud*(xM%mw1w|@wm&6UYL=fjUEQVYe@ZWY1IxyMavhh|VqRP9-wLMtkopDZ*2F`@RLb+dpeS04sJ2n>L6~V;9 z@vhDt$oz(lO>pdoO>|s}O=8AgaAFpmQQi!qX^&Lsr*fF#xq$Ef&e?o$xpb*9p@B^9 z6?x1~1rKMhiUVWxE4k46rD*G(59RTBWQmF!Gr@*4wa;vu6)S4W1JXni6kEhq|1x;| zB!aPq(3AEdXUY4r)Okbe&HI$M(3`8{S^Jdt!+6y_NhfxIgOF-LqUxN}IHe`|)FNek zW5>(kef=T#CUJa2R))h{(8S?=`Uwj=qgX|D*QkVIB_(PqyE|z4rs-!a!2`?mHI<3FlyA=AIA>2oGa)H zHV>%PLzh@E^-V?{v4x)0M>WgA1D?;r!H! zn@2b$=~7r(JpsOk$`@Cpr&BxL6SRDrR27oIi@DYEHHLfPdZ^9_H zgVYO}`-T0q)B7T9u2Tk`NstqM_g=-z?8c>#3J{D>5GL&y^=KpWkrlsC6uKnjF7qg3 zgC=(UfIltlfdGbbA=}lgurG>!m1lM%z_&75_uh&`<}K9i_IvB87MhfBdtU!z9=@J} z^X)ANL#6Of>jM3Ij6axJuX2(L8#Tp=mU@3%o`t({F}GsA+P#y(wHE8Zc|NY0br?OX zgBf<6%;~JaZ!M492lZZr=X>%YbYRPnLJaEMhyozN0;(27KVUceMeD)h41VIhZ@?_a z09oP)hcuNAD@8wUOPD*UB(}qyU3tHTHtqW3OsaPJ$TuD zjb87~N9xxRuW!1aZwPNw$FN^8$__ru?OtWRzuq6mtJ4Jh;CXp(uyWUiEBTT(rJM=@ zI$5nkK}x8u1iL$^uWEeg0?om-`Xg%4=J%Es1;e9sw5`Kn~q3roonf z7`kxg^@TMw&N|G^k|~;ImlsZ&Kr27Il`7kY;kKVbJZdtuFT`B6=k*DU%x?e=kw{Xb zK>+AI>QJA>c`ozK=84?tts~1#68?$@OJqea!P;(H8aAw+MhjTy zQDVW&O0MD72lS}rXBnFTOt3&PLyXm5s%2wAEeYQoFNg_9B%@LjBfZntU~tOrtvyFO zZ^bI^{Y;l1_xvLBJ<>LALDOvJlZ3C%Tj=4#w){7K*(6D@pdDjKY< z_YEm4qqRj_rc0f^*iy)H^tob0nP zs8Ydq%gBIf)*r0i4}Dib3wLAaWnC_9MwpU?c|*4?9l*)jiCTzQVl zeHxwa?7;3g;?I@u9@Hr0Se?s6mfj5lRC=MWup~mPXINmt^lfiu{rapY87#sB}#loeUjQevvvdP z*M#W7nbfrg*Lkqu4{|YU+W3tC!sM9=2kqGj1?_O_K2##~n>Dg^SE2_5-3tUQbH{Y5 z)oyARX?dX(tokJz3_3~So7JpS2zq0Qc$G3v0&rRY^={%^C!ONS)9`gptHhcitxtz4 zos~t>mC^$W$y;UjA<0xd+(v4%opx$%45fLC_f7Khc5JJBHXHR9F!&4H2&zi*9FCPZ zSu#dEM9Tz!S(Tlr9I8FRxsQj1w+b6Zl=bQ8(9T85&cTt6EUVg!4fT2I;#VPo=~p*KP2gyYF>{x6 zA?J*3Lpe8eduCp8#~>o3dJnJ_g@C%xCkqh|HPY*D@LVjYA<|A;!H93u-hsV1x92e! z=qbuTOX(r(^>U6jR7a584t%WmUo^*)t5t28(HKp^K{o!aEr-GJB}?gQtKsWD;S<8r z*V-8ms_rHwxa$Ov_SG z*lE!rP)K^_$VK0j`65v7wHNHy#=}<i-?csh!{4bH8<7w8Nq_94PL>?nSu8`ppWoj}_i+ zXV)qPwnI3c;+F<%Wr?;{+uJsKjtp6j?!o}>p4Y}f-*W>g(u>&vj~;Wb>Fxcpaa(wTDK6v`RBq*2}6d zwj@%s?lUdGd`5qeDr*|op~5fcq-mAfj`glosaIrH~MVUu4YU&Q2`nvth=a3@5=d|c>f6l4h7WJ61#78Lb zlS)r3%mu>N0)EcDqu)M|nYy-nm9V!)zMp|NlW&!trfur5c^6d3TKefvdHEVb#k1ym z)UdQLrN5^bow1q_IwqN7*vhekuR01q;w7v+7s;$VQ;t9K5W}FjWwLW-b%xWq*eVNU?dfgb@+~(3kbkW;kI!E|j0qVZ19+J3!@KdiECz60iR09CNr`l&mN31unQgJO-95)QKVot_SjtQ zKEZH@2<-2RJrUf;xzKNR4n7W+o4vq#n3tn2w1M3qAL>pBGpr{6ZWY|J{{OEs{gA%d zk;|NGUY{cpvRU*(4z@_FYs&CmpDXXK5noh5B)7Iib`7?iSnjTs(~N{W2g0#lpBsIO zaemm%0-kHdbA7&@k!9!{-rBOe=DGUk>1(mTgFRfab>NG}C>-z;7LJqdug!I0@$a!0 za~VG`((RNMagoL!q=AMH+v^z}=h6y^?y*x+Ogv@Dxk^(^BtIr(b)MX{3FTmD(0Bw{ z*n$l#HihPt58=xOBXOGg6;e&tZSr#BW~O4TYnE?~GrIatJw|NKD6tCA)FInzM5S*g zLH&wPOXuAs|2)`DL-Q}z*IZWBl~L{PmaMWbjBvlrk3qGn4FFqr+&B)OuB=!8qA<42 zl%qV?>Nw>_-wIth;_r7c$(Iyd1wux^0T!Pg5aOS`dEBSduy9+FNJ*1;2`sYV&=u(q zRB1ary>p$dUs7YN<9e^=sK0o|FY`s%-CQ;k1-EqfB$4-YG+qRu_Y}>Yzj&0lK z6Wg|JCr^x>_x<+x|Ls~WK{r!lb*L^gB+7->dF zwL#Z1lbZO|vH#TN6zLE&UUs$aqje+x1|37Y9~XuPC3;)A$~689`tnsK2+9qyY0(6O z4PPzH`U{*cM^u3lSrr%_*9;VW3N-88z=ECiEd99|?W8y-Awm9;7{l|cj!tVJTQIw; z%JPc=6<2&_2!99x1^&9qp($_+zxO?VX$LvV(2|hV3%cg58E?GK`wt>Tbu6|45c!Rb zCz^*^>%R?Va#3bM)x<^h+6I>&3L005FP_9=6(~PDt9Asx-z(l{znFRer+G-{I80Mnl}4 z2^Sky9v-feF^KFEh)OKk!CEPDJBZpL?say?c}i+lr`-6idUhYP+8F72<=m@EZ?+@e z+RUC`m^7H)$KQ=T4(YCkOFB4|%gSD%GS8FPGviJe&^IP#ymk9pnuy26v-gxR5Q>bR zq%3mkfq^~HIkB}*K5;26Q?tM2WL-(CHIR#}vRaj_Z^fTx@}jv6t4ba)8Lh_jOdsmE zj;9B|&5jOhRCf`dCbRf2$gv2+yqx$vwE|}O2orYFEnj@7Y8xbOz@N}qt ze!Og;uyW*fyEhnN+x6N0wv9ojv+=oI)BQTW{rS3wsO$al)ctXJP51dZ$wv2ivq$Iq z_F94AE3SiU0G7V?^CJ|a;JE$GJ_ejDVH88NW%SWRLN#QpT739^{Hrua3V3{|s_T>j zI4CTO(#WhzeMgf4u+fyi8?1xaPp8EK88!nRj6@Ib|GMcg*N;fJjw~zD>2iOaWgPo{ z7&t>qU&*i9XuKO}TiYx_h{XFVRB-KD@KovieHHbVUFuE`%Rl)n`dVZA0F`ZraQf02 zS?d6NZEuaYW5lb>nkj5(d(hz;b6CRUUB3_0#TQN~Q(5||>1t@cIW$phf|9pz<5nTe zlb4&JA5PvmmNU_CnclRFu5&UtYE0Lc=WRTos}eC1r#x&*vbQX!T%F}`Umrf)e|Fb= zI{L!VwS1j+?fRHL5~L48oC?cm5+CO0itw;6d-Q}`NIF`M&9C!y)^xn-kJr$Sgmu|| zdr0R)UqzIZy4hVHFEz(4pY9_L*bXIdrCV>&(fo;U((kcqy#m1cVE4%L#b_q|3Xc1~a zmsXVsHRlLSg*SLROAL3Jz6#xeYQ2LdGHz#m9MNTlJr%}2ODu*8EdSF0*U*9t7KaQ@ zS})=<%tsU}AtQbaVaSbu5kCa*$fTF0BguF<5>vyd~cdg%GHq3$)!1N-No2<@ikIGLJE{BHdx_9?Qp^j1n)>Bs(;fJ*oz8 z)TOY|)_+vD3Od9~$0Y;t^#7>!sTzWcW`1=kNjDwjux>3=uBWLun>hmTO?X=MFN0^7p$6H}~E40)UYA5`36({bE z;}olaQl)eisK?s%RFa#?y{aShCuVeZxYA~Os>+Zrp+|*&8fu&eIq)xf81MZF6CYy^ z$NI!An|;RuYojTY{ri3O6rn1^BltH?3f}92%sqE)^c{z$)4;!AsZb-*`6v#=_L1=| ztk1S5g-VIul&G_O7Sdt$XZJBTiaZ=vnn{~iwAd4|=!Zw4ArZ=;z1GQ{^xCmG^yCLH3%T;9dJul=}d2(uqn`}`r? zY2shHoUaq%aT#~kggI_X_t6k`sQFpYgn=+7zSP+)?KAtmRi1vETjQ(9UtI+0ttNg8 zs392O59MzO&}I>Q&2^CCk(s~=cox8o#JDI%T!E%{q^tCt@8^9Nkx=B|1d`-oZB}cM zZw5pwgSNIq|HkX~>r_^uLk=N7i(6@*;b;l305w-gJ6Cn+v4Fr9m#4)sZBX>=c74H7 zPk$qUx?Y!uHWW|UCi^-b|N5N2PB7i}emSJ0Bl~&=%ISVS-CxD<@xEQHUY~#6mzYj> zz2Bv{5_|%0AAmJ?tJmF$lY8}FzTLhru$`Z1!gm*|u3tC>XZ%$pN9C-iwV6Ne<|`Q? zSI%t0_&@=A^+WFLn}@7DHzLhJGS1wO(`PHa{w%1r{Sa_`OOV6C zt@f;GvTqDSSs1mYxqqS#LdzU zYz=C#y|PjBs{^&CQnaP_ix@O?m_yFI^;*PeS582yrrdR+LA>QIFc;b&7)l+Xcms1~ z!`vbOgI)m_ZMKnZi1&}Tn<*a6fg?~H;9=C)YxkE}+q47KQ#&r%370Xl8TstjtTujh zRgqEjP2+9;0~dC>9a$mXZ$IE>y%tdi%P5Ul2^(-LmXymhu!}x?Yz8LwT?vtW2@8yy z_qFhZRj}vAfB$vynyFoI`j9^b;WW*6?=$vSO5>EjIF)A660?P2GrA5j}DG)=*WW4%hnxe z=d<@^hr3Is{Q>t|Bha-A_~dndJ-Dp<GIxQnzNd94boA1T9xe%98`CXaCqnSIG47b=1 zKENU|)ni{J?TFwJ3OCl|fannnmmcBKCI6VJ&2{CeFwOU4pL0&_=hFZlkIxTC7tB1w zD|tcP&E24ALtyJqO!ZQ^LM8>k=?)KfeHo?Qf!xi=W5elo)E`1cFZd{{7^wbLe8hl+ z{Uh^#L#M5q?J!>V&h&CI#aP-9_i9xKlL3;)=gyd>GD&{<4D3U+XVDz1y({BG%x@yn zKAs#eH4n>+1mBBN-1nn^%cC{a6<72GEA5I4>{6SMFC+T(>9Mucmu)})GwOAjmGMj$ zr@7R(;M1A5X6lHUaw3tWxYSxU6kM(eBQHJy_ZsdamMl}5*yIR4nJuG7fb2TB6)g2B z4uDTt2{L`(TkoZ2&SfZBzB-4~{CjSWCam#*ONMM~gh)DD{wT~tq;5^XD4453tj+_9 zh-NdOAfHsZGM=>;yn@1L}AnB%X%@5@}y*G|Zo5WQY%}J7Z zNQXJ&#d@`4lfNWgQ9^M z$3zl19Gq;Mk|8TK+h#17pMoo=WTq#0+FWCKyu$i;BtN1;b9T*VXPB_v5EL|^;5gnO zGE3tBanHO&ND9Vj4!Jvx<5YJ~4TWV5PgWv2Q=Zp1*n(!u7E2Nvg$pNRK_!kCRc<08 z=DrqotQA(a7mAs-RqHGB%(0~5CUPt#@S@s2tcELCTKAe3H~D!2XU?E_D0_S8tQ6!WXF^VYNRPSiuZ`2)y$3P3?9Jy-jEB)J5?zo4qCSX@C= z;^>8cL&3UK?|B+=FjEUdAORMq(7L+3qi0m)Q5w_<@jE#4jt&i`XHFBoe3vs&YyA`V zV6z7BrGYq`OW=nL$s_C(Eo)t|2~tL`hrGMkBeW$fsEphEmD0>9(o|}9ES}K!{ZTb6M3wT!+HZ)aX@E{7GmaPsOJQ*=cK5YS;!vt57ssx z*d_lmSW64cmP;knk!&8#2zT7RE$iw?nv9fI)xZ*17W`l{2JF)p!M$Y4;&gSWxRF3y z;Ky}`iJPzy+~df(zf^!(cL%-~;Ih&uidEsEdf6A z>UJ4yc8GPKlAlAx6WH~tS$vpXSnAQB0zIzm1oA2 zjKt<7+yk)!avB@^s2T@Ns8%-Y_sUzU;m_oPG{IrPx~|Z5b|KVJX9W8Q;b8-AC7)su zp(6JhlbTZ2dQ;0+Vs>t%Gf_RjtM<>K=<$Qze zYH~2Ub^i!UwH~3Cjz1u}pD+BCSm0|P`4#8sR&6=XWuMm*5DC(}mW{M0tcM|u9tUPM zVFx;S44?}vqralDFY5Nw#;HxjP^xSS4A9Gh|UkahN50;9h9I-X#0ci1GbgI zV;g1m0d>RE-xQYK2B;SD1MGJ)+7IHOa~J^81HTo%3-hyw5f(IQ9QBVNy?_xzGFJK* zFmep$-F~((P_gS5dry~v&!5)E@R8ATOz-(_pkmyQbDVH2nt#3*bVZ7IY=Kq_LuaWhiBW`xX!w`0n!L!W|G&sCHKzNGaQRyDF~H0Ie6pUm`>8{KB{`!tOw z445e_^?O~I`N=aOLxv_x>6h|EH~w5GM z3LsKy9NUBX*g#+l(;x!=L<3pVO0C7bG-0*tdnfx>T*CRIoIKc{){51=Wyr345h4Tm z#Nv-T=*)^m9a8hps(IDkn@{j=crG;)N~2k`SN3J)X%&W>B%6|u^E0OTq$d!#49%6b zSRiSIPSc!A9&|jy*~F~k+V~qATk&g3_ghV8RHWkU<@XO7FxBp=5t*sw9bjno= zi^iU~B{rSZBRo|V$SS55Ycmdh5IxK~4t9yJ#p+b*lzd1ETFNOG1C60XBhnAwBQEk})oLi<-S4TH3g+f^GymVDnt0835jE-D*EzRt}?Y zy`A7x1iGPeNKRNS;Q$$JX`Jpj!(}92o#Z(~Wi+F;a3AcDw46z@9pUi_g1H@#1nun{iozL-}nZx9S(CW{K_SmH2) z%PG1VD6@vp+5b~Fz8OOi>tf5GvI$O)IBjE@U4yonIWKg#42ygKurPqO3*F6e3SVor zA|E)w8b|kneJ=@ve``lh;x~+c`nuSjGh|9fNifXohvReHz~DNFbCv~X{w1!D)X_@p zM)(L)*M=|@#cVD*c!o7P!4lED$R>od)&IN?VR97i%vZZ4tnbTOEl}$Oi%YiYRha!n z`Bx%CFTnYu>+oIiFJD6PJR!sr=PP{kkW@P_R4SY)eOMdjLnH&*|0fx>p2mB*>Gz)* zCk3@WE<9Wk`L`w|?ruL`RO$Q}nj=Gin4T*BJ`=h^H$#HSIZu!ag(-zGh3!x`cbQ+* zCCVIGh)acQPX)P@-8)CPv;&KBMQSkWVG+O4^dz^9{oq?1BO(flD-qv2Om7$(l%vvM|@zJYJaU@~Q zinUkb+g9c(mGNk==|(AAT49#9!gK%0hDsB0i0i4JP0j^7+<)u;p-89l=O3JCz+Mz! zWOQl@b0;NJ4G{~RgD=H&qPPH6$d z_)3i~Afj<_3rm_{E)4?~mz$BIiq0J7cxHDHbijbD6IfElNEt&rV-$eJBSZI;N`Fka zO>Hp&EMo0u_3bexpx0{vS~}2s#G~bT7WIzR;nf4Y;3qg8d`UY z2S%CXi&T{AJSa8fTtZ<)R=F6?^9v~i2YyYW<&2SOLluYcHCTs}UT05&c7gmfQO!;= zNL!Jk5S719DMchG4JquUHvPuVC^z}#EgbO>D~ zI{bB1Nqj+!j%3B$fsSZL;#rHIf8k~@@G_Dk{^>w-$b}AFmKl2g<)A@j;R}`JkPZ;} zw&bx~jv0vj&)$z`T)htdfO{Wk06RowO05F|*`Q?)GvYnnarH(5?nmqCD!r%RjTDa$ zIe?Eu24R3O@)3t+>38jND~o+ycq{wLQPF8;z-N!*se-;^oD5&_`&_V+*M-Z5Yc_1C zROGGyUek=XTnd{$O54=0$l&?|?RT;Td?s&C_j{rRz`lu)*g+rC!i(>YoNxFAvv;)T ztW4vlVsiisVLYL&w{#6Mu|mfOo_05x%^b#S@7L=s`Oob3f{M=P3 zXFV2O@f^rQ<<^qPjG+>sjI{mX(>&HpHIo>JFWNa1ygH~c?*W$C*^FV{2@th=%3WK= z(ZeO0ewI-SvFIa@2bbx?V*s-WA~Q2i1 zIr{_EnF*HPs$`LkNS4D(s{vW+Y z+Uywj-z6SJs(FsWSgHC($qSI*e^Q|T{USB<2tbDo{Am|;T1AuRIJib#JtPPZukgaU z;Z_Ir@Duq_Of|ZOS743t(JwTD|FsteoSmH@A7KYH03U_uRsU08i=BVzP@DNi3Q~!V zo)*JXYTTa|^~5;9K91c_e1I15W{N2PI8RDDrk=SLwr@6^rghc`Q6Gps?4dW_Jp&UL8zU(ky292_7Z$af#e3hjSIA zB|*W*?B(UsJl3k_isuQ;OR%;@BI&QF@mSoBv!nL2n**oMUy`;5bbmOeZ6V_{qVbFk zD_ZV49)j=xpRtn)$*c;pHd?w-l=YIeucsE#;l6HtFn{I1wNiO zT25$%pc0L*;{(snJtwv9OZdN&GD_A#%`U|H`ogqB>je4)&FX7;*VD3&eXER^9P+LJ zy&gCC4}_SsL~s`95c_<*%uF&$s*gTnhgTLzm+H9^idq0EeYYcZE(phKOx{Oy2>ske?t#8+=$~W%P?ZawK z`tMUlfnfeTVtc_~iXlKc)!?5hpMa$@UN>>3pme{V}-yl>atvy9s+;tGlkl zog30}F-W4>XT6LQ?U*UV3Fs&@_|;dJO2Yu%YYUW+7CiY)_FL`y8XyT8#y*IY_z5_Q zmiXx^Hb@e*Sz!39?>H_`RbT2xj&>3XK?AoE4Lk;sUApVr+AFuv@b|8 z#O`DH)>=fF4$+yvw6t|S9^aACzc~bAbj^=Q6FU(-IYtv0-Eh+Ec)FqIEk~F2<<)&K z=L`-fO2fliMakee1c@jUkiicc0C&PIp%aY;reoMM6_aFY1i3RF8J_IMC~~w z9Ul)0@OR31M@~|A%;8ZI!KTx2-g=#1anIOQLXtWMz(tdco=< z%^dA;DJsSwl0v&$Ta60eg^mlZ0uM&|ovRR!aAh|>@78~;U9OUEYj^l)b1bGTwm#RqLOz0ENPAf%RY#ob45XvkE=e}o5Y1I1 z+CejawXIr5AR&Y4M`U{E;f-L-en)g)L5m-lO|Ro7eA;2Gy!S2?V`vyVj1 z4{wH(Wc%}oZ}C_b9NQmHKfzrzc6#VUDP>+Q#>uatOuz-fw3JYqHBgf498m|8#Mk#sj!STEB_4T-M-5{mT?q{anv zsH(>HKQ8rSgis*EjS)9XOj#FG<;GXXoxYV4bQIe#D+{8he>Hl)EwZ<5~SUJos3eZid+I>Z`Xh>CF z1_L5Tf{|&+!vHo7(n+Ef`Gh=a3NIZhd>B#G4s&>Sz=d&)>F(E~7u{~Pvhf4fq)W0v zx-%7%lge>zIY?39pXG7n5EIGmk8jE9t1Vv-x^o>f zWsw3Ad(+L%%2cY&wk1}kN5!(_!%B*vu8)HMv9;r6{}r=lfoonWhUz(-$1g~7c+Xi> z-9dWGIu{$KM7>$x2{p75W|f{sEog;Te3hxJa;zjAcOH27NL5yg0z>UR-b$VzE_Mow z7#Rz8IaI$sJ`?#iUUxsR-W2}pU)Q`|P8>BNS(;b=Zv$Ig0l_(uU`8GC+IS~b+zD(~l zomu{TbIJ5E99Zi&9ZiMi;#H>ft@in@?zicu=GQ4Na-M4|=9eBXD*U(Isal_*kXSNiK@exVcp55E+c9S!E-xXnC;v{2qw_`B*A0ka2V zF>AfDpFxC6@bTJv`8Fhik3h&+!WbxX?7e*nLR zR|rxrD05QJb3Hp0warUH1NE&fBuf;R$*gaeMXC9Rgbp+#-gz4?pnUaip${F864zlZ z^U@hgm{rMW%2==dfjxg#&V&>@+S$Sx9|2WFcO}tflBP;q@MxLC$Ndg{VHBpY85}FZ zL#eFhMNAY^{gDQ#s^=msQ54yl|A1Aji+ts}ARdLp4E{t5(J3WuB2W68UVKMc>%&2U zqx9Q?xFJ1g>gY65(mYAdZWeUb#tUCrz=a(!n@2y!NR{5fC!t=<5{x>JN0sIx`%L^-4ugdG zbfHv=ay}OVhY4hNAGPodf2V79j6$j{EFmK_`}*WHGSgYn>sWkd*aSx}^9AyzU7Kg8 zXkC;}Mx}E+t{W=sedUJ^bS2bNMm^x%|DSi2|5v--K%$*9%M!GU8u3%xZ-;Hu3GbU3 zX`}n4l{Aa;UPbSb&U5rNCyGY!^2!_X(nH(aGQWLhvfM8|Dv~6!$q{XAnsh>!FhP2l zUb6u3G~)0LjJ9hx=~x{xP;e}jLOh}bQL-pX#t~eJgRT+p;R2$hVr6B%Pda z98zsApra zVu}nJYwd>qr_?jr)9to=K(a1dOxwnQ*nO+9h&M$=qqY}^)Ohh9(9ku8>{-+x<34Bn zeXInhMN&(>BX}*ggzjj31pS5TH=}FUZ11(G1R&eR_>?eKEfjS{XQ;S9T!1K{*ld8J zHQg_?Vtz82+S2IYjCo{)Jci8nN4tkBlCDy*Yr(_-Bw-%TpK$?%ZdM+s#G|F6TyBCE zsDf^*TJn-olrmABbwbd3zsvvKeSYwtgobPq&6gDtrM{80VxX>lNS>ruHY2oeHpY@A z9V((S>ULApQ<7HALLrCAHFyrpiEO=YBA)o$K9!Ls&cwuPB#Qrp6J5ztAK?zDq$*FW zJ^(*hJC=>Jn@95^6Xymi>2f6Xf+fFga`+X)Z?T6bjn^cdlWVbur6$8I-4JA+P3j}C zM8coDXlWrj?i!}U6*s^b92noFh={VMUQ)`mDHWEyq zXcD!goc>AaCl~k&dlMBA@e^8&0Yk3Q8yF{;yo<78qM==^^gBXSh>fHhTEo7D@8XSU z-1;DvR=;)bS+bleC|JjcZHM@u``V}wpmx(4-_c1kxZ$wXojW>+XVeyE-*;NVtv%(q z`a#hvwIY5JojZiz!R^GKGO_xk@~$RAia zXXN%dxUOHzj(2V4ep-CwriS6|$yyygXSQLChO*d@4!yCipC@vX6~YtL!$M_;NToM%w4<@4(a7&(y=8XWBf(Kfc-}i^=2#kDJFs;@}xU zRC}SYBDx);G@fQ0l9?vuulCG-p~&O{U|8rRQ+WR3%jupb;nwY*hI=DXN8J7d$+q)+ zz5fVeSM7H{E$QdRdU{-cn|2O+dgS%-hzWm2yoxzN?!;KP!-AZYGq&v(i>CBNFhTMM za8zok6k{4IF~v9y4e+E&-AB6GA@;LP^}eSQ&u13Yt9{rOWv5l{GY$+L7Ds(YHOA$z za?V;xN3T6oH~knVNGW4wRkfCGPPgq^8;NX+<*+19-itfs4A9_i&@NC8S2P{~%~$5A zRK9&(UGY-e?tdH&2Nqs{ZSH<~sWxLnor`7L+iWAox4@*e!K`;q2 zxS32wr#lKCT|B!Z;^93^=HfAw*>*(bh;b>F*gKdbUOhaHmIAXZt^QV#*F}z00ue|f zN2;R`zPM0s9h76Z8ha*N@fe`T32)MalibgTB|Q<6YSTj6aZ;4q|Vx9 zgNOgEaQ^vw@<3UIZgjMu2944=;*6|F9{%P$U{DJ#-2%&~VS<>T;xlWMV)RIi=uoZ> z3L@G;=j@Lxi`WIf$eld6blZBr!=Cu7q})eJxu@0z)=&SE5wXUPFsOp^5;keP3{DAx zHv=|HF|7=@b+4CP&AdFQ7!}67SIzLP{~$T6b6~T2L2dDdgnqwMQVP`3%LklsX)wX=#b?kC{UV-~(7;lPnKRO=e zyO7B_lAE_V60kotpT6~B`SglLNGCTaCl)d0vor{zjCq7ag{+K2*{$H$g)g}U&TV0v zf7zJI;dmF=1sGNRkXM6rjpQgWHh?W3q5|B8$OL^?@85u6Mj@=S14P_rsY^( z@#jP^Ks{Z3j=rszXG!CfLOH;mDY=CLG%;O!#tTl7+|<^VZsMh;XQFAM`LB>qrPFc2 z@b}@nOM}_eN50NDxF;#@B~uTV=f^5(QI6taMcH=V^JD8`(`t_NZshO9Bgbda)L^w#f9Z4nw&NC|<6 z(p>tTstiEvcs28`_#2_VtW;+EdVl>_Kg3=j9@~&+-G4i5=y)$uL00{2Pw8D(@8SF%y}C1&}%!4u0KrQVVfP4T3D~-{qZNiZrMB2?LQmd zMxGRJ%mVGlf!7;_vfY9>ud1zsn?Z8~&F%p?|LDvGu{g4>F=nimzrIE3K}waQAnVj_ ze^v+NX34fPaLhEh%5Ji6xf??nVuU?!3dL*6QCF zR=qNch6`_+NWd(=gu*YfbVJww0!O80FUB#>ybKEleRUJ7q+l7J% z>#au%_F>;4kf|Mf(q;fTB%7hM(Z;KR^Z_q-bZS^i8tatsJu6+R_8lVX$u0ozKX@(` zK1dV^K3&Q<%8Lu#ljK5!!gREz?n1-U@3U19Hv^C4<3~3lkC4+nJueual;KV6VFv-I zdnrj`!)S>g4-yj$s~`+ZM*f(V|LTen3@T4c4P_Wg3}6kSN3Fv+$N+?A-mt=*1VA4s zg=>PQtr!lna|y%fQSa|LhGCMURC>apuAv&bp{^^TNN@Naln8I{W_R@eJ9V~tdmiEO z$otI<|B#cO9>Pt?&AC%QPGyI*!XAN(MG9reGTl>~5Mj!S=Vg`av`P^ZDEhMfVFaTj`1t*JG4tZXH(YI-;_M>FYPd=NnM7i zmeH?Q-5$lPx2kd-wl(t0xVH3B{`C_>wYhx8<(k4no$%Ye00;AVFX%4YruV2V0GD+5 z-Rm%(Hh;5zpI$5UlxPxth|`Ppop0CsHQxuX`{QPc?&qDsU5xJ6!=W$V_2={cw@?1j z^~vY!@pv&#=j;Bot4koK`$d`a@hP=RP5bus^p?^+bFM2uGM(-H)NMZ%Ta@;P=d}B1 zec;5THHe8{OWRTezzy0Eo5cvv9b&WMCT!z>g5kqYyk#`?HxtKZ4I`{YXUkzw6T*vA zJ*)s+y5TbyTFwn$F%le zs+BkWaa(k(JKpmvkR}U-#y`u6)rISCaJ2fdV7T=UQ?h#gCBGSw(ck~-0KMhqfYw2| zy+`J*M;0v_=NnlEwLu3Zhw{(z@0sG;vDrAGF*L=GR3NglSWDT!am`W_nU#f6Snkcj zAE(uMoWrD{!xjSan%ax?cg#TQ&^T51!?a(un0Y zU}fCSmoPoJ!_fh){LCvep-hzFvZfzlwrE8QUq>E?OJo!>U2&{-eM<-hf`9Ir2^vmx zs6}Vc4LSAJ-zxqO-fI$<)stdYu1pg(w?Bi)udPRP)b!)A5?M*eypLm_O=MBo*<>Lsqyqu@0Sp&5m&&a+>ge3 zCS6C%(&fbveS)5|^lHiyFp#^ETW))5#En10OAD8Tt9KXwVS8gezuDd?p8prydvv$k z3$XtmwpYquPV@f*kN2P$^@sS9@@nGj+;Q5WA|!ZAYs7{hXv_bkzsKv$3+6UM^@PUg0y!n&Fod~2rf9aq<)l}Q#(IOsX-9kZBG|S+ez|fj!t?bb`cmBDcddvM^9Km- zhJFZJz7YJiXebVE^J0RYol_of+>~(C?3CxyNpU%5fv-W7O-tZ^Fb%T9<(rd7O#6*X zhWyqxn~q{L!sD-{rqhg?K+iko$rH-f6bI66bY;ONXSG(#a&TPI1O2Odxf?$OVzO2S z5ntqlZ5`Q9st;%2aKtFzobFec$Uqtcp)CKzPafiVZ_gcX_zTm;S(mV8Fh&rgyOunLx&yPF$oZWqbTmHhVV#ysn=2PlC;zK#(@UhV%tzE-@tkirH9 z;w^$k6n3Nvg<`J_{U~{S(cMONlJ$Q*_2aCUXw>*PgC|uN}*-!gI%1b9Xpc zrt__>We2RpHY9w*yVQ6fK8D^242@Xh-9Z%Hg(#tv7pL z_)$w(^`S|ufb@s>hqx{~1_yz1ETxvXxJyqH-&2HzN2;L47evJL0EC>yvr%V4uP|_D zbc&ye9?j=KF)CHMs>5}>3LFo4M%+>dG|ru)M2>r-TU>Q^zQ;ehMb{0e=>Q}F?&bn6 z)?vRbh5JrMQ{_Jlg!w&eVutgwx1my_ymMsomf5D`*TiAWL$pJn@+13XL(9KoGBHmo zW3u$PV+S13Uwi*d7(`)^(w+21AZV1;6YP0Yc#OcJwU+ksb6wdA??ll)Eo~oX8j`C6V z74+03)m$L-BA&j$0!LWq#a2-L^#VR9cEA7B)tV={EMOcMtkl7tXARvq5tRIHi9 zL55o*#>=!msY5Uq+M9mr1H!O5vB??s)waxx;gNDDJQ7&$qO1Lhx)8PZPI~bmJ9-Gn zFEHvyW(78|zfEuaR1;y+T}-U|jrPMeE@C(Rq3KH#h+#VqOTO_8o=k)PQo%#_sZeR( zRB#=$cWXOscRekj{AzY1=J4nBOGhMw0pFsD> z%%p#HBzi@FQ8`6urbz+KWu^tO)UJmd0J+51=aW1mEKnTTJUlQiTN5rst1W}Dx!KV! zQpF*fB*Xl;)%|6ZE9)?jezkSZk!V~aK&D9K7hxzBx&wFg_RvRmeRpAfWz-)g?9Nop zk#>SeK{nNb|-C6Kf{_vEf}FPCzs47Ix}@+V%N1^L7oUJudJ@jzCUhe zo2|Yst7fOQZ#V;vMD-j+e2a-)imRlj4^@sBRnIyfcG=l+vwwjgdoOaoWnLB9!xy8= z)TyiI5sj!3nL(JZKli=vbiU1)OdenFB($h1d=eC00vycH=u*k;3Wi15ghJBmhXZ2^ zIek;Ydfh_>;mg$`o;;uTXCLma7=z?&i*(8HeOJts_Cm&)5MXP7*PfgyNG$c5ca2jD zNRr9s=W+8;E#X#xw1-6%Gc2J)=K_>`B%20rZ1${KHJ~@Xt6>vQJ(bsjqx#${hSE=u zvj9swn1A7{^h=Iq%>x?ZwsOP{HGBNqS~GuZHuz;YRAm>4NVzlKcT%ndL&zlZ!Cewz zg1gwFmK=?tW=OoyIr}JZ7}yZm1#Mb>L45UyD(i}Xb7km}rZe}Q7gGbhZDGr2+lQH* z=IWGn^zW=unXHH^{9pmEpFBX{4sl{)^8E3_d`_gLUvuI18q!`IzdsZo-g#rSFL)DD zLujK9&8oSUxJ#_hM6B64M$#E?aLZX0O?^sZQn#e-%*~ZHxuVnR3wG@n!__H_&9(W) zL|*TV$!BhMtpW^!aQtgyCx^^Qh9E*BIeSO}I}A3j0@{tWJ>c(6=Zt&$Adlg78X0vC z@zom4lv!SKjM2C6krbffMsPgr9WRm%?OKp0_Us)Ou8!mK>2{{d^K1jb#6ElkfhNPV zgNOaqZd3k1o_9}RZJWLEV7ElBT0{hpW?4+4JdbOmF*SN{e$}BpXnmgHNOC{(nhmZz z*)Jt4mbg=({e$NG+RPVWAMqkrL|0{d5leEZg7I=JiltDv*>Ks2pE9;b2uwp4!t&jh zaF@-ezfa&WPU&*up4PFfa`Mi{*4*?may(w8FfYq==cc8`Bkn-1H)D>{N#1v(4puZU zJznqszWI#sa&e8MXTe{t@QwaX%=$V_pq~rI zP6K^9%bA8v(jJ?0k9SFWILkSGaZZcUl*;*d)_-8LzA3Z~nIuQF0#P*k>mIQ`f4B7w z$5MRMjfj=dL{GYD6nuv2lxY^aL*{M0Ql-%^$}>*R7i-&G_`bi>wyd{Z_u&##SPvD=DP`-1;y zENL6sK?IQf7hY3aX|#ZX92$^|r51>ukoh1LB)q00B`Zi&^U~msrZY@Q;qd@9OFQbd>DQ+hLcUZInZ0*4orZp1tN;EEz4fjnT%4 zH}XkDbAe}I&PAxG`}>;5%~E9e(8z@T);RNYz>PH2YC&Z2lpD_@Yl&u}du?eCTr|Mt z(~X^Fyhm^xL-GLuAP6I=aWLfOE?Nkf$jVH*(b~G!TFGaxD$(=AezcNQ6;0aXQeTn4 zOwf|44xA0_qTvi}^Z&NwL#JJf4wYA*C>w{+< zYQ{xqSa4Yj=Gut&f9QJ0@JPFEUAyC?!-{Qml8$ZLb~;AKwr$(CZQHhOcbwk!JnP+i z?Qb9J`!TETn)j?aDnC+V%z0ho9M)0M%>&g=!W(^H4vl!xJI>JPgV*B=ZJB~F6Wyaf zk4#@zGs<+a+0w}Zrekc8g?&SDsJ$S=v#Z3+Sreu5F#DHLiE)uXn?|ClHFT-ytqB@io2 zVC@TP|39T&YYJI!tnQb!v}c?z>2zo7%USL?(FNV#rwg?qjcEf%Qn`xGUX5p(^}nRP7~2IO#`WRUlD)CJwXBgFk}nJllgelA39vjw$Oq*=8fG-O@@r z=NTpZ7>EmZ$(iR1-GjCg&oN7f5KqpY{DJi}D(mz}k2YA;38?b*ZzwPv0iR8{nJV#7h zRr>uJZKwGo(ZWBHd*DWJ(VYO{l^?y`Rm+9Z7{%*Ctf_qbmQ;0uHyi;wUUb3u?OKb* zheWKY;7}k(7~dSx>xP2ko86R(l_GE(exVfTUbGF569esD^cw}Z3txlf9O}YZ@A%Ep zP8!~U!AU)lhhz^}1@m?C-VqIdIi=U(Tl1WAr4xx?Osd+I?_d8tw*+Z+rQQn{xDclv zOh^$ny1{5pgdv&<7MNb^wV5CPcfK41tXlf-eUT$t@V#)P$81`e8(dD)&#kr=dCD}f zw`Mj+=9g$69Ae5S;mxPaPi`0$r5cR@wt@5Vq5u$=p69`e9b%i)m0k}ipJ%m7v$ub? z-Sp>of3Z{To|B27f4`>-*S~0w`ZKgPzg4vOQB<}E`_|M@$v8zNVx9TLao;2a4oVB% zkH1R9JFA>31uCHAO;NG+uI~V-54MniA5~oosVj;~K~av^!K-r%b;(S1Jsh=NAFXuv zOmmP3oss^B?0Hy+LUkwuudnW1DuCCsEZjtZE^6*RpF#P?0o{dp680*t*uPa#+mO%> zYLMRmj+EG*!ARR?s@$3bG%Ly>LAwmKf;l*K2q`GW0-*2$hY+a&*Q~%0p$}_-K7bdh z0f!%IfF8h?pE{%$k~&oT&nzu)wuQ)qVen@#f2bk45OM>i^A~Gy1%Xs6rwM~_JtiBw z3BxMkzYDkwfeR)LfbT$PWQZUN^Am<0R zMTiDXU?9Ry10DQ6YK^kl0)?KRu07vm901%dF){>m)wK2ZYCl&hW$yLEp&N@~HEfvX zmvTwt#9W<5Pch_Dd(ch!x-8OoR>*QW|BzKSKmFYZAT2*H(*5C8zO<;pNYLYi4m4J$ zR7LE{xIPO5V;n3|`qmmT_@u~*vArf(*)P`_fkb1qh3rWYjshi>(aF6+u_r5~ZqHP@ zbCWNDBvVO&;LeSpP5lq^+W4C<-lF2?ddq6>N?eFk6nu<%WOMRSySdVX<0De@%#sno zP;v{U=>Y1vXC0!4-+Ni=+a^A&-7FKgB7v5(1Em65B#nZGp({gFdtw&i%FDiV9ogZez%mkJ zh(>lxB^NP*A{p@7R0vkIfx5!}xxEMs9LjSQQbxYCgR|*ZR*c)2AYou2P9oJa5^xCK z4F|vp70Gpf_o9k|YYIZ7TGL*?X{TMR%q%KrSdt&nX0yqRn_DR>Fu|+U@siVmg(b$Q z1zMWYj{D`?+gGDB<{;CaoHo^|2Z1LU51)F!E5LmIJ}mSFs=5#tS{OnJN%UHjDr%!P zXMmsHJ9Q(2MK@%_%Di?ch?)0b%Pj9)h(MMTS~cKTy2H)sGiNE9IMwhgPTeV^_WLQz z`65|4Po)7Oxjg9AVwjj=Jin!8v63ESl%vU=h{6gn-Jr5mg$pJ(pjiLp}I4#|!gVzHG@&hS{&SfR;ntjaX-`yB zM$um{RI_mjZ$IV-)zZihmd|UH6Kum-?i8zGwED=sC0Xy38pEECA=g!%RbKFi7lUv5 z67ajCu$JY9H894iyu3_laGY>bH?QhK5FJDkoHk=|0RGlv1~Z6aPG++hzE`RaToL`z}K;SXjU8G_+mn^g?#=|x5dNIie*R) zlx_@(pZDwrg*zu3?a0$x+(2%Q1i*MaTfhRC(maMpa^nUMj_lotcdmh_>F%uOYe1jo ze+vosoA`3VGxR#Rk#c=E_pMq7>a?eN-V)|UlMFDvykQ*VT!h2vKaqe+#`2;-BnzHX zCFQZQrNAUZ8$82^5r%M=jbG_=!S)T|`DelMJ8+7}9C#1$U)5p|7X@-~b>-!0Xm!Oa zw5|rIq14sPu+9)4r~Y&6|HYrA8X`X`@m}DfjC?aCAV4tWoEfZ3jWFRP^RiAvXL{2> zo07)>Z^55Y=16Kl?4REPFhQ!q=kk_rD$rp+i{^R%@U08*Q0CVPArnWR?z+&=`RXJs z^PLtN>jsb5pigy#^(0kyV55^Et`FoP569B>$b8MD{QWH1p_u7@zn}P}D-CS6oC8!HPPPbqJpXJp z?5zAfkpoHyKzPUv@5jZ#*~PD;h8-Wuj3MK{f4%?SW4M1(haRpq+< zUO4oXj&`#BPQ#IQLzbtfk+{nW$P(t<2BpU3P=CbuOE12vN4c=k)6lB!5Z|CiT=o5M z1|iv9!rprfINW0%z3cn{I&ZAKk8&+=0#2k6;^^K17VPMgD5~CedaBy<6p)jV-#mi2 zz4Cj2LIOz-zTJ*O*cf8`&{Wj3eSX)aIvv;i#8&H^)^PM)^ndFJrSGH55=7^mtqX>0 zLle5#1xF%=rQ0Vzugy|1)_W_0rqM7LpN(St1~J7i2_cbPd|P;7uvWAh%C(~TO_^9* z^5slVA24;#*S;;Nb0AKZVshqOp>^tn=E*);cPC%P$o&fnS?&KTE8zbfFgO=Doa$DG z%l0esjLqnvsGKtVpD<0#!KCdWJEzj*R=eh{+t-`S=WOPiO};m;r1W+1Sf6-}N7P!%nOg@)d4 zw92+Cuh*^YOq~(QlH@cXTwsXDw^1dDqDSb;qG$bQe|aic8@#J#AJ>*+_H1jY1~i21 zUBc~vCRGOx;giGt|LrmDM^ZNa&n|OOP%q-t>9iiebNX!%*1HVGCIF$v^$K%3^`-7u55i zdHS4+E!~l1H%)0^d1|fgiZTqld%ofh+Nr!C+jrjCw3$zy8YT9aO; z%t^|QM-{Z{NdsEDAUC$;M$Evxwb5seu4Ud5>7=%YrQoQ|EGTyeq-i#akV=fsrfM@~ z@Lr6la1W%YaIuoCe1*FoG4SzEKy@N6Avz}Qz|aIgy^GhRTPAZ39mbb#o%oq>oj69e zOhoHY0YAf#pVq=oVfIX(#VN&*gs$o}!TM}#Y5WTGyI~{vKw4i?v@guu2nIn`@qFJ`$P8V-jrdm zd|5_Rd{bn5mWX2vd*oh}+QJOOcq7BJ$Hfso@t4o(zN6VbB%M`26S(X+B!xbSksGII zd9Y9ZFff&bD#lWfVDIpAv);15;<4(aKR9u2@Hb@da-#fT^I#tW+Vn?}rv~-#jc8Nq zhw;_>oaSCx=GLBOW9Hj`4V-eGTG+eOA8XR>V!Bq$=tX0*{8mQT^7Tg8z|iQ@-wpCS zMGye8Lqf`G*JZX&nyx0gLsZa(*Q(ElQnPH%raIDtEe=CaMQzKj@c(GhVtZdsx}kYF z+DOgLZ}Ql>czS4bZqu99U0-2g5_H$3kjVpX@Ka;tk!&U*MVrH1`>{U=m(x3PY!PwY zd>_%T{hDU#(2pB=IUq6mc4SYt}u|SS7aTed$c+x97N$za{HqsDsKWyoT2RBCs zexKaqKXKPY@d~5`c6@yua?iUY_@A5#&%1MUYo=j5^d3sjyE3!hUgctP<2M>x0V5KR z^afSDY<2M9XU1D#E1>6o3oGuQuqG}S_?@WHH~%JmD;M~~72I;}+=0vpcKQb{!`r$) z4Yfoa$M9K5up{sphVXm*1yF9~E0Yc2-faZn-bZTxVn=ga_SB?uZSQ#CxQrUS&(cfd zf<@q@p|jCoQ%!lWc!)H`6=7cQ9;i#joQ@O^6(s?N-_JgGE4=j3#-=)OVRwiQncJ5f zXnb%Uu$<2rG<*t=3Lz!(`N}>V)3OkQyM3Qet_!)P(fY8lR^Uomzb*d0CD(Wt_ZMZk z^sY+dAw>_A_Cv^^@I9Bbp*f3g$c3@n^)~#Dr8G3l`nCzZHD--TM+{@V+wCV|<;$0T z;A8TV5wqCSIphDGzZ_eX!a5BSKY&Z%yWk;uC;|hNbvDo0&+Dz(ZH`M8dRp4%!DGS5DIJa24r*8l=1pOZqzJ8s2JORQow$eCDu z;^77Z^-v8Sq}WMRdWxVUcI<;SQ*wO~pu-_GPWfpOIw_8Rh=fTteleAhfVyCaE@g;1 z;z;}k0|z?3t^cv;AwHW}!xP=84>Pia?k+It*Elk@$S{RWSX%C3(%Ei8;voxw4=_do zVXj<15@0m!N~$#=A$s{p>-OnC?|xL z)cVng?U~N)0P|A0x*{h~rsLX+mAhCclroH)ORdEa$>S}`S3Y_YWN``)46!w#E$%%b zkJNklhc8lM4LZm24_`zbckZc6{NrXhdUbfq^Mt*lWRk5iQI)u(F--tzO=q0yUr)H4 zxx|sWCth0-@eIpS)2CisWh=tga|OIN8}df0H;sfr;}46D&E8aI6mwDRvS=`5Z}R^A zd3#E@rjZoY{OXD}bSKQ{o)DhJ@`3A;%Hw5GXk6`}!udxid`VU-?30kb<`J-+33D|~ ztR%`&aVKIeVzO35gWPeAGUhA=k$(9v-KlM$JHvhy)1|U(#F-YI8C%IR3SFz9ZuYW? zCA|vlhR9>6SylaCx(Jz+ntlqdt|8~rd4I;->3DJ`xF$J}E>bNGG0Had`2BjS0HpRv zc{G3S(XP5IyQ2U8DU}4a&3oFB<*oLz_(!*{6yt@E0-Zd~}}#&UCDEcx;GA zC_V9B{`4{Gpor7|rDSA9Jr9`YhBqp|f>2au&>p=0mx@u}F^2GSJ%@Az&tC@aZ0LOG zuBUPIG*PB!$CD>I`K@-KkA2wbUA}?sQ<_)p?O(pg#|Owij@s?6(xN2{kjb1tS34`y zL0@~-|MIO&)GLd!YbFxYcKmBy8KXfo;-i(YFps!^a##rU*RGG%NB(Z)q9)X(n1eY? zX-Nr`GNkDP8J*qI+AHC<6vAqhTtJUhk8gmC5tt5OwmH`EKQczz>^=AXCpp9ODbTs^ z*mtA%ztYVU8HU1~6)!Mt4n^KlMa_iBxUe4j$67#goc`WB6ur_kWx# z%v8%69HxtL9X~_d`>Kdq=|qhNj-0Fqq6TD?RG>|@MhmGu0-P?>=xt@=nTA(YlLf(c z^1vLbYW-?v{Tvi#Fuqgn@kn%IJbi$%H+b1MtyIzq=XzzPa+a?Y9EdxJns#0<0<{d~sqJj=oAI`u{v&#>Dt*fd=t>WM#JDd)pm$|~ z!0^9v&F3#Hq_8OBt?zL~y-C7x_-8W+a)H2h+F6Y-w2Lb?;4}Ymt!VnT{C{05)Cm-} z}>d-VPYbw*qT)PgJblg-u?FA1Ogu|JHoQ77R#H7pEqHN_=Jxw4ri@j!AU;V?k+ z(+^bvzm5u50p|o>SPB7W)J60#=af7ba4VpNg=~1pRRO>|*(PWpVj0xAbuL7OQ?Bf0 z3Vf-eYM;rVdqS1aB@lp9oikbwV9CuGnT{6gYF#@KiXl7f*3wbryWS$@w5>j5M16s! zMAHoK=ryg;-D>ppsy3)DCDSU%R$YM;dAM^>b~(|Cpr&91(2LbrIl{m#FjGb-#OE^Q zfW$R}=Tiba6Rdux44+gSae;rKA*i|Vcz}Jx0%1doNcb@%mvHYM`HccANSr}XmzVI# z&&Ch}@5i-!AHG@DQ^49wFNwf-I&MH>nXuBr#^^*`3JDz|$ZB`m-Qk$sjLv`pJtS8R zMkk`j{>kBke^zH&XV^pX&SzSi`>fou5q-@;~4#xgc@*4|K$d{JWnD>Yh<@M7etzhGfofmLOf^+eDK* zMg`z0hu%k6NfahN1I1Cd2(IGxf1MJq@&fhl!`%ja)dYv;z5xd4c%;uZhpOI?Sh@27 zEM>K-B6xm6Tp}g&Brkb*#k>F~4dmAtV>_>67m2IOyO`|ul&m}4WwdrYUE%%2{MBkaCFXq(^hL|!{ z(qskrbQs*UOv{NQ9xuUFE+qO=#aAeWa1FImYUz|gL6iP9H+^A)=q{qx42W{t3YZRT z|2Xw&WB3z=?#08GY$Ee9NgR7A34TF;TzZj8zD;Jqsr;qJf6VI8FwD7bin%;EUlF!A z=t)VrSJ+=l?0={NU>UfQ90dF?7eWq<7xCfo()L$#6~ZCc?uyI9WuGGQ6L^WT2W)8z zUz{9oY!Uvj`dN?-|a`;iG?Qoa-JH-TdW92}Ve$#no}c*@VgZIJ<7irOD7<%No8A!480Wou?ro ztmZ|Yi0THl7$ZY90Y(sSk|=(o#A`QchSd95CS#tQvU%W7sE7oOH7I?&yel0xkQ`8p z79DSJIYdx->AN^jn52ogUw&G9>hhubr~x2Ez|u-h5Q%~8D3|TICoF*(cY}A7Td}%N zn1d-HQ{&4xP`d#$Fnm)494Qi$z3kVi^yr7f74-QG9wq)}R^nUfrNJ0z`?f@u<%lMz z7YSp;kC3DmpOLpz5+9?rfzy&?o=S1E8>KW}N#l`>Mz${c?O+|)QNtL5a=E4PVM}f{k_=xf ziR!v0nYmbrFREsySC`YUG6LCZx<`xb<1!VQ73AS>>Fc)oF~Q%@x{AV=FUcPENn*N> zwGUHrzvj+<|4k3f681|V73oaU-o-C6!R}dR_1lEs!AbX>{Wkbr1Yws9Yp*sLumf;Y z(ZCjq@1qumuzVX{btAB|3yw8djim&lw&4ENpK~xl8}?aZV=%EIK!Nz_Zk`)DzNR@R z+cg{5Tsi)SL}Pg#i&zErUya7{0+lEtpMEN4%_WOa)h0u{x$82Xp-Xpbw zv}1F+oluELfQAgAML35HeJ=)>kdiGibLUiq+vUTGJKF)9XzeC8>Ki|Y&C<|4PnrH@ zRC($LeAhe)$gRB~<8LrvN@%Vc2e_2w@#@@TotX^6V1E^dJ7V2Ve;$ii-jrG29z{6Z z8R)hn{D{AcK({ziP;im9;uh7Cdoeyg6(OtO@IZW@>(lG_<3$T%v)etR(#uu>rS>a_ z=!Oq2!M!>7MqloTu+QY~c^N5EDR;|3g9YiSQH|lMlQ7_d1LlgucBRRg+F0 z`1GK)r5o4XneSg;_4DJU(jZ|eY%7&96eWAAzU1jU#6P(l2!w_?+Be6hKx)zVrsaS! z6KhLy_4ZV?9dWJ-bxRT<)VfFuX-g7FC`p3ch0&oY(4uTl`qLVIs>*4w9b;YeG&-`U zICN4RW!aXOx{(ry12eypSe3Kygy4I3pBe`tgGqn!uK$@ z@7-6it$n((Ql!z!GA~wffBM2^Yp=iNl^GO9cs^Pu>r+cnP@LlbeH@-aLUFg_8~(hg&g?i&H&bSR;BVVXz>O79EGeMTcFlT5bkRGvH(%k?0Ru1Zq(Kj>*PsR&F z>E{_06Z=y5SoG7hrtm4$cfbxW!l@uj%W`M)f3r#)Su{_K>^S%~>a3X-MYd?<%1|+a zqDBF8bI)&eAwPW!s{ZXkv5Yt!HYAIm@bv6{RZk_p5$)-i@jG3XvSIs{@a*Wc6l%{5 zgF3QnjLc+u`x4vMNuWk{HEHPV8w9Uj;UImvVorm>V)Yd~3kiqYR<&byQ~oFFkf|`L}83#fQx8g01b$lyBlQ zV`Ebse#2YaJ8-=lb9OWD$rR6tPoMmIK0DbC8K15vwZb6L-+H!IbRqdp&p+aM{Wz!2 z!v`GK1(RzQ1;sl^5x7kM>2vT;o!14wY&H7Ph%6xZKD`RHYRMhk&MRH%RY?Pujq4_`Y}F0;77r zsoeY`%^FoM5xH=0QhAYrJ1#bf35oa3>NpME;h1M0Wa^Yt#%JNU&_FH9;X2DhSNwf``OCq!ACG)LnVWtiIQO&WwM8EDeovzxh!QvRT~ zr$)B}ZD*2ZBqDKw7MLgai3%m^=L{(Oy^EFLF9HYqlzoesQH;J2CSS+guC#a4{(J@ zeI2N2t&()rGSFEI`QHn>(Y>O@`B|o#a&bdhXcptwQN;f_VnGv+zR6fBMQV!E03Pu^ zIEohGCSpLhOo?=qxgixT?465750Oq(n%#dn8l^3x3jWw8OoII$qM}sn*y8hT1$VO8 zEJ@Eo_Vf?v0xf-{u8vn_X@F&R#_~kl4<`3#f&$d=QX|fV^0H|0k6*E~g-QjqWzsq} z%z181dxKyjy~;}IY?>T9K@RzvUXvd{U>P8>e8Ni)bYzknR5G)Kx-&&qcS1phfPK%4 z?u|5IqYV+pyl$uJg#$WGNdPf;cj2s7qZRUkuG>5^;`E=Wvp^KGs*i!O6jymsQ(y3PKaLkIk$b3hyN%G{($P+ zsDQQt-V+km1VRp!p@yHkf_5I-QcvFNrP8LOze zpDN^2T%$N?JjPN1XI>hIhnI6zYM7be)00l(90*k4m=p>94I(vf@1C{Ha+^mYM9-vX zPrn8>2Zcf0QOGC<>y{TplZU)HZ7pCvVTO^9KV!<%E?72E{2gWRg8qwa^ZR@1hC0#7 z!zQSz|Iah)lY=)!Rr8Kj`{ZO91@P~`+RwBXelWVA{({ql^{sB_Z{9%l&C$S1&~LFW zt0nk&uPq?IU`!^Jp8XDA+7SQ&~h{=R`XacKi=T;mSM0ANN#H8SThR*0wZ+ zZ7YAitkB@Gi6=E=vaKO$HreEdJWEaxbJ@?7{Mc7crPb2JMp5K+9o`z+w$2FuM=qS+ zf%R(*a%yA2UPU1=q0 zeG3VJ_Y^0R(rkAiwT#uC2(Cz@fF-GzEsWt2dT&++q*G7InQ#A@f2Bu~&IpTk&ZKzB zxcwaas2y+%XvzPJ+RFduC5+25h$BxMWPedhA^45hG;=@sQg-G(fq}B-0PQxf!~_aiO;Uqb%j<>>&X+@^~X)F=Vm!p+Ef}bZXtxw zz8#FX1nSi<2glfh>f_cnWt`PJmH63};?Q0AgF>K-aURvd@(7A8-!ecYsUC%ii+?m*oru z0s98j-m{3OPvFW5w>w6~1IYf5OAq_q>fjq7WSTK86(`{;VDWj^)dY#<>pbFUL=-@5 z)Y~75^fQ|N^c<-_unuG}G@eM<*QUj%>h zmOb9zyiL{3xRhx7&^mx_4=h0W7)+9SAoP)NI9Fa7AFtinGG$I=%J@E9Vdh7P#IaMp zy!BvB+}(OOux^a(OsRhY%qVZ9xqEO@#8|U^mLq+#r&FczX0)>uVCcJFIS&|}MQPXg zEKH@hqiv3(<*uhgFSF!dxw577OfK9M{l$iL6Ct66&A$mHLiYJEl9$Y!(6_mH;U~7A zaFze^&bblp#O2%3_;bZ|JNjg3^8N~i#?AEgL5B5f*W`mR}(1rwgMg|a6Z!$1`@5?m(7LDN&&gU z+IwTekOrvN%36wN&WKa2_r9mq1966XJ%b_W^Z@1;Du#Yzy}(d33Z+qebot%xL@C44Gx<1q)b_pW^}R)YbmxX!c$`` zVW$d|)Hw7S-KcRAA!W_|A0k5ky@f2xWGzzv?EabzIL`|+tv+o~5nbKH^#F`d4*}gur>4prRfPj1S?lLJi=dbOZ(f>g3c%>n--yUjQzZgdAj5qYU#~7wpQ-j+h0D9 zzssBK@g(5~zk=%O5LFiT($*SqaQ>#HAjIe_DgA9fTdmFxy*hI$ln@^`3?CaKHSQ?j z`=Arn#7MCM@cZW*fyq@{Gt_)Tc5%#BFJ)BYi&(@ww{=okP7+3$xgJ_(O6dsmQk54Q zqoSQ5s>DAs;ZS`)go-D56O`IUQA?UuMxk~5=OCag;#YL%@nk;iaJ*>>Tpg|)ct~qZwUZ zlNpqo^ZR-hm|v`IL|YZjA`mFItqfAP%f>0tJRoeA$2x9l9WVyHw463jiDm;!(T7C* zPG>R@_8VOc-RiT7kZo-d1kETV=ij!an*-?$VyOafsR}`tog@x6mC>Lb>o7bBbab9- zw5&gOW-3nGGNdgT+!!xCCi1_h^xf?*=d>=GPND0h(g%!NI&kj4WzreP@;L8awFJ~X zP;7+eJ77^yy5+3ME33`)5Tssomya0Uo+N4A=2}4oHid^cm-6YRJ#xAv@J;J2e~y!( zR;=3xJAOZND&<<>8U@>7Qo7(Nv_|M=@F`wsZ%t-`r#(qe+j!5TvoKoltv0>vyWPsR zUan_I^E?z7(DAFZB^waI-~F1Qt!d#?In9o&#@rY)U2w}ve7SkwOq)Siu=gNSr?Wlc z`-`~$>^dp=!|poJ*VUb#n=&~aw=;#5=}@DEpXYAMSbwGqLK2NqM zJ|BBmF*ZKGz79fKY<4soJS3x6Z;>WWK%Uth0X6FFg_IvBZiB+ZvfpUCN|8|j-@$ zj0}$G*c!qFU2Ru*#b+S7vv^M7%skntxOu3kAvv>JL{i#} z`ze8v1BC8ZC~%FzO={b9dy)Q3xCq}VicZ-*a8u(mjd1$x>Uq&*d~fsa{P4ZKirY7^ zw1Xt?;0jqp+fX`6nXLie)3*+A8rr!M8GRKFv0OEV*EDR&pmb<>)p8_C-B}eQxVorAj5k`x2tRSDsN~Gnf3P>ekh6fGOB$4 zp`=p$_QCHlp)B%;a_P4nigmAS@gS{9Mz4c`58{W}BH5tA$Xu}Q0B$ai`0_~HC?Mpm zAG)VAS+G=SoC=Qx#L~pUCEyWL|B0okI z<8rwH3;lAB3W$-MjF+$>!nZj?vXCmZdK;{TgBonqbHk&1{vpfxd0emX+beKM2Ac7{Nmpe!ZP{OMx|Km{f*~GK##yDg;htT-&U&{YttTSY{~rvO^Hce z$>aM?i79=_`!O~zmKYaOa)Mv@hf4$!L4(lX{ruiyj}xF=-s=i(^w~mhmFqk<9q{NR zOju9PTm)=NdZ>OB-_v6&;~xi%4-gBLbK~+vj}K5GHb8p7-``69lsCVGIgP5MQfuFo zx#k^~1Sb|lpJ|CBg^Iphoobj^|{^8)x{xV3xlL3<~Ov2&ShX# zp2ftW>P*JO5n!oCM3Ys2jOm=|f)|fx%oTeOihGYIOw%0|nN`W7=t2YELZRW`j;CsrwyMUPcv2JfJ!^#R?w`#^%}?Fwe3xM4@m`t8zbznu1}{fv^WDSGT_p_Foaq;wRpw0tQP*aGlw zAq);E;FbrD)fJ2|0|xRjGuziDQQ=f?$7kTfUlC@0w#${Ifjswxd0S)4Sgfw?c#O!Z z$Is3xsYPBLHc;~QZ(&6mf|F7P`1#iHOIJq=%#az;vpVU1vb?tVY@}GV)h`(tO{cvX z@Ik`hajEv8D~7$pq+x4~Ht^)hDXr)9L77bUk%#U%IB=6F$vhj0FuruIFG&skM(kVS z4SMzn+@f~ckN9?hA#^)AZ57(0lCghnu}Dc#m5zsJ_Q#bOuwZXq{@wF#<Op1+EV4HtiY z_4K?#Y=4I19$sw_{N=IVLp+^8Uy6GWy9)bYDf5I^7@!-ol&jSU=AdPJQgk!)T@)%( zd{xR-5HaJ+bf@Er_ zn&bx5gbhj|PqZ1gHbajj?=B-}YWfO|JB-W^tZpNiXj%nP3^@%wi4jI!cs%BdUJg!A z2KrS3Mwcep%O5-s?K2o1BSPC8xPl*Pr?9x94dIGlm)wlGnN;YrsrzUOg+|)z@j5bc z(|Qh%MCzu@Rg(Awgu^S~uBCNC)rE*%P9h#&xKblAo$oRK(5hXqr!j4jPv3m^c|L z__W3N{fkGFTH$n`coQNN-MDal2l)A3lo{Pff78b)KB~mQJrH!gLq0i06b%yH=<&l2 z201|xs0|Pzy{QT(eUZue8O-GeA6wMI65@`#U6pe5s@l6yC=FyhKvR*Q3q{YJ6gjhE zc~=r>F)X@0nh=|4ERAKnzqhq<#nh$3)3K!NR!tyyqU6acLGSIVq>97tz#@SpUDV`Z zRQr_vYystK2r8?j_P!?%iuABPJk(-WK1s%Du#DuIsFdUyOI~af zdlB%AxkwuE?VnlT8fr{$g7Z+N>K;g^K`Za-=++W_vuZTE8hrmx_*S%^P!2IP9u$L( z>;R-JL1WJ$9_~1mK@L{dm^iN9H)wnjaFOp(^aO^u7`p_E8rjex~!bwgjO>5Yt?gc4-l}lf|Ld z)xr_jArDd@rb}##+)W!jAh*3FEs3>VyM4JEL5*I*v5Vym+iS_m^8tW-F^YKmW3kX- zSzAIM!Xf-9lRzKSwn8&XCNVW^5CmEfB>0F&n5X^1s0iUkBJ6fUtFk{b_Pa|X z0-$$K;N%D&o?;Y!uYyyYw%K(Oavz%yNl1F`5#CdV-ujD9;r7iugSLTU=E$Cym;64(;Wr4=P<`9CwntKj5HdvnJK}dUf{-G#%P^nLAvXq zSX@>?vTHszb5jXoy$t1xc&Yp)O#VD?GoT8BO#4_ZGG0PIc&q<3$I{NBWzSZ^CC)_=#(5NM@a z_~!rO48Teqf)l<=jA`tX})=ngfW+Wq@6O{9OLr!4@hpGFvxsfiG6{?V4% zPl&TuP)F*N61ydcEbR)0b%K86s92ZE1}@gURGG@>yE2v7Pw}FA_|pJUk`(k4A@40+ zz2)m8++O)fH|GqZ4w)8{?9de>0!jY~TPr{`OW}C~R9gmY7pEVk~3q21B6>Wr?6VuHg@z(rM~}DY1wX$&YXz z#s>=IBoE}Uc(|~_WAZrroW~?*x_;Jz^H5TQR+JR!^wF(0ah*6}p#3Y7J1o|YERM8V zxO_SEww!d5BuscKPPp)oII*eKnny6ERs?C>Kw<0UqwsJU$=N)>@$~T&Ev!l@URLV+qo9k44JA?1q!Ay+GdQcZ$oU}S>_ zhB8CoApfzk!@JDe@HueO1X@R18RNhe0xCF5E~X3|SrhZ*V(W+E8Mwgz)1c0#u{c%^ zcW8t8T;LP4FDu77B=DwS$;OE@#=on~6AIvgzt6zywlD0)vAN@u^}|zh%ybKpO=>xz z@Z2hhdwj)}NEJYd0=QOUE$z_5(9p!aKC?Rclfl~n-=IK6Wb(EOt<&Yk-H2_YAc>!q?M1dLeVU3GF4Q7mrS0c`f&)Bmd3{+lyVD>K zIB5HS%MWnmNxKpyHqA%fuoK8HY)m*5C}8O|Og7?=3d}Sk;>V0h z?E!8dyXl5c`MkpO7d#_Mjnb$z&yX|+%&C}^-1}c(g-tC>TVd2xt;VBBc8ZB(4lYdh z&ejg8y&bXXopV!es7u*kJ#9gh6NY>a-iKSO_HW3f#0JLKiV18)J`5M)MuY7pp#v;e zbm;Vhuu19j+H0HlcZB#c(#3g-Uau@nGc>ztr+Ws;XbL({Uo85>K9?kl?kV2RPJN3b z1y<(d@0y1$rqe1nRtS5v%Dty?DbSgLH4z852`(%NiotA^Y+Nt<;XvA?Yw!*zeTFQe zPap{IT7LKE`XepQCFP_(0>Ep5bkgwJ3D#ahv7t`g2qbPs(wEt(K~W{(CRl#S_d8qj z=%x&2Dv7K~U#9D5ZfWJ%%tUJXEokebD+hzMLK^*k@}wd(Am9D+J;!qV8yLZu{Bqqe zt7=O6wJ?MV6IV*nne4xj10MIcc+Nk;VnJxuvBZ>rA!|AJOg2UUYzF{*{&&egSp)Dw z`+xEFjzN-s+q!R8b=kIUv&(juZQHihW!tu0)zxL&wry9P?EhM8pM7@RxN+{6`ynG| z^vlMVHb8`d6>_Yia5OW)1ae?ZJ~kPx0Uhc`WVSYb2Psc5 z9-+&A;R-0TlAAJx=#kdzkH0cbseL1uDL0rJ>UeG&JHyQEU9U%q2a`G(OGmwnEet*; zxBEjBVejsB)?ny8$zpXbf2$*{-WS%FAcbyG)*SB5MUtOIi^fec(M)|^&5{sy{M2WH zcQ!rH3fkYg%2U_`?*eB^Bo)pPA*T!bEAHv8yMuOxP&1I1j5>X>B?yAi6wp&&=kT?T z7%4N(#mByJqZr~xC(E~!GddM?&eTLUt0CTFJml+(V5OV1OA!=8ab3;GhfPLQ?{>Vc zW!c?gwD-cul4I*fWu_P6L+aA96K?mMv|%a@F#Id5QQ_Lt8(I*Rqkr9|gCFyemU zBzp~&nXuA70Q#;uj4Ay&K&Ym<+{9_;JM-r`{I~IZOC;{a>pvA45T+(r6N7NDXB>94vhFSY}*R<1yZni{SCE!Nr#8Yu+m=Y%lcM2JIc0V~aFtFw*aOh+v? zDI&BnH`w=MzC3Ym)AZ-swgXeV|*+_pSxBnDkr^Znuf6Fj) zEvFu#|HP4#Sz2LH7eE}@diYlyDK`eh5tg?95l5oTrHXD#_=_C+1C*$?{CLe+9L(+E zE|xChO)hjMv0(=?O zPoF%tJ%#==YxTzbd&m}GtN_UIFP;HUtBaQhR>+|S;?w9{ERmU|e`n}?uc30kIZ6*2 zX{FSSS6!6^j~bb?BKPYyy!|v)L6K{c6fT#$hcQ+s2PSMoXsZG#d{|uH`4f5Hk75&v zbw-@3X>mR5^>%VRX_E!SAt2{|XF93B<%gn}*7wkItMb2v2D|{S{gmI2-9W}8e{{Ww%vSKzU@>ku%y|MK)N)mqMlTGVinXY%zU^R7 zfEzDOTBzvt*3u+f^AGb(-vAADe*5W%Wv}q(vRL6g-N*T9Kv|5~+N|_r)9}?~X2s?j zPOo;U-wZK5A_t@{`p^#fl?7Q5jIElj%k=k=wEg%(6T`Y;V4|F)Z|0{aMde^yuzBS`s5Vw{Z5a#;UzS}d;-8|957PET6nn@kEHv0@kplz5>X>LxZ9kvk}Wcp8-$2f zR}6XrXRSJbuOykn!+80u4(s4>BQ^OWE7pWG-t>;_$m$cr8Xz7PaxvWbzB<<8ahX_; z4eRsGy`{ns99ZG7JgK)vj|Te|M?czRGbBImwisG_6d z3f#zZ5if~d;N&q#VaMhR&5%NiOPggR`yP%GMzIl=@rb}ksfuYx%2~Tm%1FOLKbY5# zUVn-1$;1k}R6J#Rao#_yKS@Of8*hthP{Ir6C~hAfEsqnIv5qkS)&?0BI_UWl9>Ivm zM+YA*r8w`J_IRS-IhIE^hGQb9L}sgldwap;Eo7fZ#0Z4uWm&DKcD?7gRhNl)DX4MK z(SE_fN3ivPdU6~Vb`#^tw*rS&92kV%fxn}&0?iaT))L)gk%n_dL6b065v?I=MCY7o z$@#jKR-x*}C$0*9>L`9Ea!R z^>RgErSAkv8YtFVi_57&soJS6V?8ScPugYomz=v{_>MnU(e%2Oz+|{#Se6?Qvtp6V zIBL+Jnh9n%MPRfs^+0hnxExqW`og@+(#-qgdAB+gyYR-NY^0pM4nD2#u8LyRR)%m0 zSqXTajJv9{cJ;E*I_==BxA4u^^RDR3%*Nwgl~?=3)J%yJp}SS5Z_~MECN@(wJ7kje zMuo2f;>paKnQT7{Gr2qWl+oz|_imQan%l7nR;(F6M2HLF;>=y?8GP647G0QwcQp~E zjr*3W?(H=%X#W#XmI*|nW(OHLoQtoD_` zE_D=F&lf5J+AbYd7)WDQt%oURsHyL3E1?31(fXDZOsRI71Bqz*^q;E^V;7>Pnu83D z3vE#{cm@{f4Lp^IR^}3vNe^5r$@cyzW2>@J1=OPj?L?1vf8nES@kn zH8D|lHx6?h{Z}ZXCvHbQy3DG}qxNS@qL|0QkqMqgZwE^Rxc7(&`tsb1nGm(5Ca=tT zXtNPdZv&`5HzT0-XM8Xu9KDei>dk7&O-CeMU(J?@_HgEVu;d>7=O`=O3(D-SeuJhJv);H(3u<)$#}VVQ*_G}mQAp_+ zO(T4%$9T^Y-wY>Nm(C*WE^h{*7xi4e^W3}eh6S*cUhB5Ph(0LW^xbQb-lUL+Uj;h8 zw3c^vm4`dmEnYkHvKMGc!TPR}N=>cH*c*Dea2vSkDsyt`9T-^=PA${>um6ZI{*m&5 z=@nLL)CH2)AN;l#PFY6NNt9;eQK2nzCKm^Lv#;BOrnKSR`AdBL4ngZe(XCqyhS*ue z*a~q?zY~-(J8q>7)}GQx!ppM)tuS4S2S;W*7Owd4%J8_1&k$OQX${#b+1)ld!y|1< zrjt@`!hMT2v8t2Xtr>n6zKVf}&1@v#5Z+wYPCo)sOm`M@y^N#GA4%EaSaKMI<`CQ}t$9cV4 zoL26sUoHimqI+)1>UU^0f~_{cKjcO7tfCky;YULRrPSBRI35~uncs!H1dt3o_7a*! z&^SRFAQ!QMNIrf`OJ%TNn}f;MZ#)D%Mp~_b#!&-3c2XIW#ps#;2_sSDbeKYy)V-&u zhg$;Qlfi# zU%3u~I3`5YK7vNH*Uc`F8f1K`Z4>YeymzK&6MzxjNbp;eGhzYDqd}WiKvdU^kc{SY zha;|um0dtCD6VT;r-rQ^?TGB2)Gl0M`*+vMM_R4mL1)_aj|g6{JgH~iAUAx~A$Y|L zV@^+pA2ZK*PeC}Wbd3;SZ%t*5n6Hy0^ z&*JwaIT~;=R|j@)j(1Mxvs-k(|&3B|rTwRr*gSosKb$uEc0u*Pf{z3?yN19tt7!!DBg%|8NX zFEWWWww`zLZ76_wB+<|P=B8-*x?F1w^v@L6C<6|iOaEN`E~iCNKPlZnTSA!l(ACFW z#yHo~Mi0GkK$;@5YdJwZ?`SEfe#F@#t4h>kIk=s- z9r6KJl(fvi-&E~nF}l~Dp1m5|&e4!fO%y7XO;DOSmd{8TH)~ zqUQ$hj1L7`JrcLHyFPd0E6;`lDRELY1UoeUcLsQFvRzXUbSP?*&#AmnAvoE^s_#tQ zvssTMrmi*K9NhpL-l&+CM4e~BKm`jn&2kz3U`3ZB?A@_XO$SM)!$H7{yLN-Y(d(3f zf-^7h!`p~xDbN*`L4IxTdf zv!stmoG?Y5GP^LI@-}L^B&bnlYfz?ZQRe7S=IB;_t@r$GGDEZUd8;*WqHsM48hT2- zrCfZQvW(i#`uXZ3;MHUXTSp6qG_nWjQm@PUVO*Xoru6c&aF`|^`~<5|SPF4PMEqMk zYRZ7Hv3@oF8oDv80{AXlb>(<@8Y_G)emWLsPSGqx}Y!M{QpiYlCLsGgXlc9a7chB7qg!Y-6I z=jZa{f28cE#o+5qR|XN^UQ{otFFCUO_m)S4wuEnTnMt^%txCblp;ZL*p^AT@aXRCI zQ9*H=ntT(H#Z`r@8bBH>x$tov5qMvibW{teoa&`6AYr&;U1xPsSzM>i+Lo0o@|DcX z{5$jd# zMTmvpY{bJ~DQH2IjqLO-2_a#sl-hF@<0~V{nj$OqL}7}WQgl@iR8>;{+!$Zhm+U(c z%7YKS7D5#KtY%Q_rdx+)u1nK#&BOseh(1EX30z4{u=j-EQ6=_NUt>w~hohUBH;2euRA z7cITxQ4@dIvU#}Rf=~PNICRkCs|qFw zykX%{3e%RlL=4VJ(|ry~Ek}D}W(!fDvag{AM$i~K@a&}Hr|8EVzVGo*1X4Y0or8i> z*X5w;-;cq_pwVpfd3z~gUb0A}Ht636VK;EMtOkf^s=e8iS1I}OV-_3J;8L0uCwqw_ z)6`dPd=jvsXTKcHBjnPEKxagFF);3uw?nhr<@6&lpAj!;pi>;Rc+gp>k~Sx0KvSBT zTXDLl-P52pk$x3w8ff#SBe8e_*jbBbg(IN=-plTVJ;vuT$2V*wMg+s`R41sEEnuze z_Is@N1MvM7;z8aI2OoE^Br)#dLdGwBD`$6o0I-hPls$1t$0uamAM*bE#l`o!Pll{1 z{rP;!HgRV2g<^RgcN0dz{XYHe;DCGy^Enc~_IJQo!rs_Zv!*>E{4d7JX)x{WKgLoh z=;%2{L%$gk#^M00{-}6M+CnpZKrMT}@cUYrcYsVIxTtydCyi3f9bMBT8jHVkCukIw35Y9`cDUQho z&>R;gqsn&p`Q_s7qgv=-X$1?OdaOB_nsU{#iTXI)JGuJMnPKI?^U5T}7o7N5lq0Y%l);*Wgb!V5e-e!ffn`yF)BkQYIVDGnvF+UmTA-o2 zbl99MC90X0ZP#k#$ER9;m^TNK24tO?YhvVf`Whz+La#ZtkS9~HlVyS(j{CmNE#zTs z5{X<#s=$FYRX&M^In%(t$2PdoG6iKBo!dj%y$#p`$|=8#w|?us$8*DvAtt=RKe|WT zT^GqlaU?$@LYO(7bakQo-ADoi&OZagvSaoc7!3B&){}?pk%Nxef39N_@5&G?T1Q?W z*2)8YO?A^lFLifmqSyI)Hr%*2-#j_(U9Ajm>ECsSw($KPSZF8Do@M2C=WLG9)y-$; zY8W7=AX~Vv8S(8rp6gN1(OfpAdW`)M6Zt?^6^!E~mRF|^`MduJR)n_l8&YP@V zpqLH7s`fg7?(B=ZF;+;@+I!vK$tdcgrEacaux9HAKv+QuFVgXlZ56b%PLLJ{26D$? z^J+j*So0G50PTi?{mA!$fG=d9&$!3CajwxRS#!RebcQTWFYVZZ{VOtQzJ%Xq(@rK7 zV-^%g%qIyZXuJBXa|p7PX`yZh6M*9fr#4`p=Ru&zd}a=Q}yx^72(&On7%&%mXR*0h^aZ$O`*Sr~0nrv1G{4W@~VFwQT9KrtXf zM^d>?-74+Z1a<5mliT^So7(n2d zbD4mlko6e++;(%))^hAwW0U!B_Hjtjb0)v`rV4fU3{X?L2VKa_d_Qu$XP(E=JR)QK zydr_#akz`v?0pekj&oF8z^ao+DFkIabGqy|!K5Tf?8kGN(oU)$g?}{_1}|Tkrjqiu zy5TRye410_F@L2wJ-J^hDE5$>)_13^qfkE6(*?%etx?DGYH>a~|GfL5w9OaUkNd46 zt|*XIEhXCdMA${ke+|k@|8}X(^88I`bAV-|kTgGShC4u`cDbpt>RoP0mNsmAp4XmkSK-51K4N?hzeR9V@=1G1ZFxhNcBN^?-cnCf__1Iz$RXb{BkhS&I`FTUY)cQ65CM**Pg z)j*N}GEMJfc_9|R9tUh7V?mNPV~tt-YSu>9fe$(@ZLJyjTq0uR*+QsPqc-Z+i$36d zc0s<~YQO3(LX4T6&dDObFV6!mM6bO4lEz@O}6+R5v{Szk9O{m{y2r70gJo+U2wj z+(<#^YCB!cCg8^U<)zb{_EWJ2Ja!cThHQ~OmRfBYP8SM8Qyx(V`PWXHpMEh4IifNM=BpsSp!4L$M?sBs%Sy{3cY6(PTkE<}9p5A0r*YV{v+g!&(@tI-5CN*`pFw>W!BICFOhoVQ!r2a>Lgs3%h z5#s{eWn`)1zf%=|UVT8YJozFa0>@tWeT(;Af?6U#s+$I;4z&?5LO_Yi{w`9$%bORZ zMI!yk!L0nl+g0xY>d`;1_}250&* z7Kl?lsU1_zN!wBceKLo@YvjYW9lYwX8g?~*l|R|dKI4r&`nsB+e#aF{@T~%$4$Y3* zAzh8BomNwx*njNU1O7!myTANO*8r&EMUBlD>3PFiH+{}qy!m~s5e4SPN}}!wM9^To z!%6+!+s;od`JO6@Ar@ozbJNL~PHf__RylXMzb)k7Ki_d6L&@rFBnP)yY!?meR@hl3 z27#z3YvGo@u1{j-_Ky|rLJMlAxhpR39Koie ztTLIlyjB#s&yp;NnW`vprCtwi?8OZ6P=588+Ow&w^DNZK^R5%Sn1$ErX|EGGv=NMn zc`!m74-bX;HJbj8gDI9|XY+QW)U~>Ixs`(w7jb6?C)w1Or01$9+6L>~U>px<{E()4 zH6zS@ngAOO$v|ufmORjPG99&bV7ha)a7u4$i_6%UQC6yPD;&J@gVfI_9*!QO zd0y_D&B0vsdX~u-Z{`V|>+B=OUe{?kkfW?lrz-qo!fK6HVX2t%7Jp51l<_{dL#HCx zr;M|rv(SFUn{RJ~oo~NCpIT@q;ds98jVw=oKT&F02hO8y_0BBDxB+U@E967tVn$1n z(QaEYsJ#Oh(rvXoRsy+Uw=p#VF8DFEhK7;F5uE5{e*cS|OhHp6)-Jxk&tP|^wzmt- z+ZRknYUT;Zd^Rz8o-xo(%MjW(>o;l# z;YbVTM(#8rWD%M!$99K~<~7EF#hsjz4m;~H_<{9(HZD(Ib!Y6)ppMv% zk(3-f-zMDfn$sJM_bF>R@3qmRlPcFa!8uL+-?Y-G_Iy!Tc5NRQ0x%6cdYH_ARCt5- z1TpZGJlF#*pqx1d#Vat->hW$XCtK?12KD|XY8z;Uo0NHZNxe8T;20C15bfV&qm$vI ze2n+vYuGPxr&$g&8aZEZhIAjsa47E}`g{?PlJE13_|`YhwGJ;^$CvpxHE?Cd~;gl_S>C=~c&jaOv&lP>%Ev(}~@4lif;c0~?qbl_S51r@h? zr1Ppai$iMBs;Lhgg-hKkKfmr@rsCp$ZW@J?tr9W@9~`FQI`2M5n5A@b2d^Wm;MVi_ zwtEoK$owl5E6?A?vLBOsML-{41CEmQKBA36Qaf!zLVPEQC+U%}IAIW7xo=^~Lf{4- z^p~&MJF#?1`ctWycW-bJgluK~eN`?=uvU1z(?IvdwcvG3?`)6iuJi_)j0Rt(?%J*C zwM!(w>Zq}HU)FPa&CVr`L?cUp2(qQEz&5ZsoN5!MO z!_CP%-)H2zw(9)Ut?R~s_S)7*2}#w2RbJ>F4#>5m)o8923G}X*vMTcJB&xIYt?=}9 zXj&S#Bicshvd|pp+6%2T2J)J9b84-}@||}xk?Yb1rR}g9jg{FMZ;-xz!1qvH@?Eht zPeLMFx+!f7s^@*_NA`paBG9h^V+M!c)TnT8f+g;_RM+^TM8&%cW=L?ByGhR2*DJ>Q z+s(kbsqaOX6>nLB)$W|z!R&i=GK|6aam2Dc`wRC*P$v)Zz|Aoc^gb~UAZ#zxT~?FH zR}flhFdp*0XKcum!v-yO;sE7VwFre|icL6_bCAT!+*T34`dOLr~}JX)!`oBjX_= zG|e>m@M4CVkIjw(bRJy|p@!=A(SDUn>E%YHRbDV3#kLa_pvQ?ldgRwp5@or%KAHy~ zD`KxM+GUvtOZsTP^JjG&KMS07+03I>zm$w22?8KvZ}JF4Y0w05MI5AojyM!wMB=CM zge7luvZ`~OpFKuxw7HH8t!hdzKCEB*IP!RVxY4Y?2ko-!s7V+eR& z>>xr06`ZZhH?VV~Uob}dO|ZqQoo2x;OSjmkM;9(LkAnNgaZw-wh)^@HjdI@G(ox9_>iiGF* zkPi3Xxno=ee{k)y6piWBEqHXj3~W45YO((=c1(=n^rU^*Kjg49vO4{|NfJCYKMTb6baX?LjYH0r5%5lnMK@ zL6H~nuHJc{z|C+YS&B0YL=}o4a1aYC$7#e>ic^1c zqCY}dK`y+tL{8>fG`6u1H?wb378Av7nz|788DVc`wZ>Y<_}6=tn&y0oGd3gWy!4b@i<4 zm*=!=_xJma60f|gPnW;rW0OMk*Fi>U(f+C#D*_hg8D1<_2zyxoI`b%Dn1dJiisQ=K z_KLG`B>t)79bGeeRBF$In_DNl0eGp&aRxz9g35dL6GF4|ImO(oPqb-Q-K`I> z`;DzLS6#!Le%BUTcRDp;R&*kI^uL7r)iymDmgGLuwHqE;8h7%F{nF(+ z{EfH$e52X*-3rffKJp8qL5Mcr~gcUzsm6ayndTm!~ctEPKo)xJcI(y=r+6? z!Uq5`k531DK5lQ10J@Xc=kvti{!;br@k#fWhs(z2*%N#BpAOx)z)tVCz3zl$%oTYj z-82Si&43vF3yQ<`%Et^Om1G2&7JMw^9B-;OBaz_Cgf zMFI5y^hDNiX80g2M`l0|=`l{gB<^q`wp7z!JMhH-$TY9vFVa?tM+_;Ke)Sp4dS>R6 zPPh97)`F;0Zv3|O;;dN&kM;Fv!Y--1$s`4Y?!R`fNU>li1xhFz!i%|_7#29&-ij~< zvV^&|9;z>sa@hczr!<@1e)%AQ-9Bd1aG^d>(+=p2zWv%nCo9sw@AV{c|0p>z}jI ztF(y9=bq3@5pXD1Oh6Q}hS}P_ij3#Ss~+hTGT1uMBy~`n&^NjU(ukO@b@Gauq=W8t z(pQ>td^|Ay*0`|gFfMgPmGZ-g|6Y=(ivx3{CM4eJ_8VbG+R$&~9JyrQ#&(k10J|5e zzb-M5R$x}3=B-l5Ye+fd?PONKz*7!6H~rfJ$TCo9QF#UAwK?EIF0}&kHZcdyZzk@Y z3dmY`Ji83d5i$4J}B(|aw4w|GIMk-OXJyonn|k`a*}W= znxC;O91dVYqsw>s&cH+nkTq8)sx#ZH1wbNDePa~IT#*08qcq>q=5+@AA3Taf;2EVD zt%lL)?ebJ6zB_yK2C982wmSdcD)6T=pb9)1vF2R{?;AI;GmlRB$46{1mE|Et=D9)F zL^8rnck#o$OpJeAvHR#JMPnXg(QLwukNwbK(&_e#v+-@XiNw;md_0ljz5xrFU5 zxXnO>8(6I+^l=c&d**lYstw8*V4Izh=_|3YAAjWkMNB&2o^os9?OW9m+Y@2?ZE^t} zyUdp8OxfnvO$XuBA)NmpCi6yPep#vkq&R!z3h_i~z#fyQ0zZP_om}O{!Q-wykz*iz zNG69zP4)>dk^307CgN0tS%FTPpInEQg^Pg}eprMAvkLDy7>PW&g% zB%jn>xdu^Il-neRwV|aB#{-NZaJa5(z-{hg(r?jWV0fN6r_CUB#iEvp8;ZNSbhcmS zeEg?*3T>hX>8LnCT0-f`2H3pPp7aI_T8i{2j*&JCsyqiOH-e5OzoE_SI6woXra3{f zxMC^UlP#p+4L#RlY|GpSQKak=&KZ->!y59Jj7&|4RMUQAS}Ps3*)d4}Bm53WEj`oEWDvzSR#hS(^&a5HsgTFXZgGxY|U<%(BojYa9PbaQoPl+Nv2 zA&tdz^XYmM!2LRw&J)nLOWlY3JDHWZ65P8U;{+zkKEe{e_}2^-kaZB5YP*j}(GsZc zE5j-2kM^>_ZZXXZ+M&+B$es|GaLxQ&L_*xV1%(7TJVJej`?=;Lr16Vbg%lAzL`uzW zkCBRuAGI8^-dj}qx14XRKsM@u>EF7+S%JzSS=F@EVpx{j^>c;1!YCy$s0&SCsMz|h#HzCN`iwS~@wq;alkqta*rU@Ic# z)FDP?wjPL6d%F0;t4O8<6b&J$V5qGSDt=vGq!()2RV7IvH*hp;WXFQ0(ll6)#2_Mm zhl~dko75A>^weqm$qz!b^T6{#h1F@ok}Iz7h6(CT4m7*Ec6!;5in{Ldn>0~%djG$# z^+em;%vR%THV!8q)a7v2WC8lM*I5^eis{rDn&)kbwj)M0YemTyW{0EX7J5DQwmq*FptNBh9$;X^sn?8A7elsJT=-b1vIwyBzQP+EKlwJ~HGJ8oyf& z>W;EqUTMFTYdLje!(NY|JzS_tcW0pu%VLfLY4gQaGqv}5;UpA_Zt@x0At^$|7Tc(l zGc=%vpqu>Tb)6BlfbSu?1Y_egiSCopV41B0$FlMm?hk5d;TvP@oi3)*~CrV)mfQvs2Asc z{on!Sr+ywhTtZSNtK*(#I+D7+tVBzq+28{lA|LO#sMRs8!}mcAZfmdbzT6WlMrT{K z)#yuYbF$;-SZ~7MCgx-&j?J(O!Yc1tM-D^jK-(e}-3OPBCqn=Z5jWYisWt-@p-V&F zdl@?xW|P_7Jg`6SqCB;V%u*eAEB)@t1LB#0uJ5yumR@`HF;I z_eCToq6lIKtUV~=e&6x_OR!$*n?WqS94!T$o`jW)a?V(=Ov?1ZuMrqxLr=B%wzaGs6y<>3A%`vyqEl&a<1 zOhCa2mtu>HFjC>?%p%oTmvmqTa0)aZl&{;AJEzynuAuM%_3k#36P&;ioY81h(du8Q z`*APVBAamlX`RF~l9X$=(hYrhTza3#RYk>RCoKJ+T(=|P8)cYoyIhtk7`k{V?jK0} z*}Y}ti*LWd7RxNbugUqj{A|BTC156|Hhq7dwsvp&?uKp#Zg=smy7KVB<(uvN=N**l zv}99Q9|E^h1R&dlEf=x!vp}4Z$(Mb*%hl+2k)suCf-q*SQH|jLVrg-lCd;SRBf!>1 znrXMxaJ`V2Znw;+RRuL@yi8xzo@=+HaO-)9YrI^Y%XMA?(~euz{?C0{)gh_||7yfI zi;1;|w!|w;F@x$2H>@z+i4e^V5`&0?-|c(F1z|CT))A2A7E1k3SlNsL~ zckvYbm-nAfR2YUt91DjtkkI(tedY%cVp!19(|v{6b^44SQSgp2%6%5dfBF8`UXtZ> z1pW`-KWDqFbcc`C4ADQX|IX&kEvUYhO<5W9YAc(%qn}-*30*cR8u3PWDK1%^^TY&) zWm}H_S=?T||Lld2S|nS`R`@S8%&$C1cFq6aWEfPzD{B^uIzgJH1j`L*m0Z! zd4t|hZX-FR#r-4F-?xx2#dxwJW%IJ|!e(*w!G37`W;i@6`=>lMMes5;Gk2#7fh$;U z{stvr4LqP&fI~E~#vk?UU`^)q*kDci{y@Y1n9*x45eQrX+&+LQ{|-%H4G)OpXyxNB z?F2W?AttRgA}xac_zruUd_oW=z^U0OW>oG5Zt5ux|H#|mzvZm~Hi7f6ysbqettiWe z*CmGa{Y&0V%mMNi*bb1lckllpZy3>k<*hFfAaB#>|6AT%|C_wQ)&5_|Tdy&$#J4aR zS}@K~oLLJ^Pcw@@q^B&1L)(YjC3?*`?9Rqnl2|&7Lez$yn7bp3P>4$^9)9Y3keBhr zh~#P>XPp~lqI*h|<4tr&KSpFAW*VEy`)?A;n)QuKAc9bR&_+##V9~?mzRO2H=^cKm z<1@XZJBm5iO>Y>}aTh8MpLUK7MPou@hery*Do8Wv%om4FA{dcswZeGtXKn{WL<>O4 z8%oy_Y*GY!CtjBDq@@F!j{T_zGI}m}kG}4SR?`N>+@|P8mE<7yhq5P(1exs%riBw5 zTfP?VOo9`eOVkrS$R{G#Nil|Frl3k-UoY8XkzXYFMg7gzWyoUOO7(TG0b&1YhpteW z&b}Q*3U_f>gsComy)OtI%Y3{mv3ZLcZM- z2j*t;?iUA1vnEk%Uy`{V6@e#YwGt_9E>}ehFv5&apzd!hTCe6pr>0R^a|_3pA9q?=`}7}FsTM==`2{#&iDBlNmq=kvd_q> z^lUD$$D<0n639||1!rj@`L13ybwb=r9Z^VC4x4|qs}3-u`M|OVxwbH$!+l*&TG_7- zhbFq}+I{vK+i~Nq^{Tk`0$D}m(WirJ{$RS)VR)vXSlW=zdsYEaTw!QFEMH3|I|b#6EqS$&T#P*?iIeT_D>ONCBZ~v#& z2Kh8Y2}@Vqs#K%9?OWnCv&OZ01StMbaOMwMbb^P&j4ccJ5;iR<12v1;GFq}6ZL%1X zG}xu(dxzUUTa&zDF%je~%BR%pD$n;o`%Klebo!YX=3(TG3zvgr@XxCV;+ACTe#y^) zuRARb@cBWHcsm{i2pYbTbbv~r@BH;+S-jBPs)Q#pa>)PTu-&&^s}cpTQ10hYK3sJg zwbg+g=L(1;m=xhgoJ#b>-9=QIeHf(B`@TqvP!13kWvs23xSlAw9H z&hlJ*?toe}ZT;oNxj)nlJ1A8ecK`>IyZx!$zktUqPz*{A2j3$#=ThAb3|b(ZMtbuQ z?lUxw;MmfmP2eJaNW;AkPA5s}UuyM7lQ=X5#f;{&v~Bgy@DhCXT=utxJ-=>6Y>##g zRBU@Cc9<|0RNG+Z9FxehLpaRyZ5uBB*?Y@&B0-~%x7`8Kq&lRzFje%><`?!}!=8MJ zw-RUpY%a9u->%<2%{pg1ndaCh3~w$qG>t#%rb9Qa*AMS`tISjPiU&kvW(A2(wa?{V zYEdJE*NqPDw-oU5VKBGjx|)YQZXt$8Vu zI$nDRu`06{#;fHdAi%uJz$G4=tHVz{Eu%c;6PvkI+Jq|5INFF89iobeV>Zluw2BUe zG#)}ITE{ekE)&8f4&xD&rus4SefqYrSJYYX$!ry*c|8br12HX9M>>lKQ`^YgYO#4( z96y$-fY}%abHN5VK>{k8=x(l7$jFBLZ1_8B)(vPJd^`0EnVme|7L*6_^Wipl!F19C ziGsfDZsMcS*1=XNL1`!X`;gzFg$FXq1j@wg2MvK^61)GH1t;ft#-C~3_^^X!{$DaH zK@|H(`+U$pe@;Yff*jH|A+*_4AGU!J;yOX%lvRRyaZL8rh_@|f{P9^gfYZKi4R2e? zAh;VB-M*yb{GI54MRha*qBwNl7K|Ko`c@mIJrxNnjgV>q-a)hrSA{Q2A<$|`{#vs4 zbL2v~8?0(<-DIds^E(<%Nspm#~rri0>p5M4i8;ga-?4{h-ziq;cIDWVW*77Sx2o@ zu8>(&gWEteSScJ#pS1yYA$mVp5A3yNWUa+Fa46tGRB+XQ+Hba(?vo!&kXd%jtHNbv z@ne7J&dMJ0xOh>Z*`hOvn-t}3eBBU5ITYO`^|&+W1mQ|pL(BGluA(I`Zpa6g26ml3 z>S{mvHWD09Zduugp6>MJg1yQ?sn2}of?PLW4f!>tAk^>8d|(yDmT08~`skPng-Oas z0O^*l7&Woit);e)qK2C0kAYS8Hl}Kwzh~9hWM1_II@yVg>1a7u&2|jfwwLfO6CnjL zJnD>z7gohx_b%nVYHAy`jwY3ulN9 zWF9)X3XMLtsIlDUd5c7kco-glAeHtf`SmnypyYo#4f00$P^C$=^!P2d5 zJXHrw!DN#ppJg8_pOwa>O}q}ZpHlJOAl@=;_Se4f8QQ(O==W}p11tkb_I$kqtbFqn z<$ed)@mWyXel!L*4#~vuW4~XRjRab=xu7~ga1R=7^{U-S2luJI#%oG<3H(3aZ;o zlS{Qd*PqyPO3!Z(v+5hs@91wwas)oLF>P;Or zP*94wAfmIiJdIS^A=$8KZq1#6llaYNiM>9)q*!T-s)z7oq*2_b0F!(>ufci}${l&> zEMJk_&o8I1ru%#yLrcpex!cuKq<7Tf?5k`BRhembFqgS%k0#562^!JnEAj->oht<1eA?Pi&O63;OeaVAxq zrFVRNg$0^bb*W*6Q9NVa0j!OACG<#UaKkN{aw@E~ebkDP&ednDZbjmd?j^tq-Sp7%t2^WYmhfAZ(A?5dLd5dQEMl(NO3)4}oLN>cin}l`)}dFSpuYjUSi# z)3*l|f9DeA_Gq-qY5noz8^9yyIfg~(ngIXB(bCN$l%cJenYMu6MN}7GKEDV z_R0U7eIzpUn&PDca&BsPi;aSnxmARP;{)?$&&23nfJLZ4wg3~`+j?U8xMS=eYcI~F z7tu#Mom6j4cbrcb2i&vjhB`W%dfqM9eGU3j7`~@{)N)-oqO*F|5``fLt3&1?^&Nx1 zY2sl?$UqB{`gJAdJ%Sl_F3WMfd1G7#i;x#8<*zjt(qEqj(LP+fuQ_A7S6|O}GrDxX zAK&RT8;ATxnsFQ(p7P#-TMs;vaFtyCysH?8k`Jn^?DYIE_TDO}vZhPd#oeKB_l3I@ z?(Rd_iLnQf3r^Vt^bsMN>JFcz@D|~lnFY2( zc_*VA529CHM)0Gh4YlFBiF^1FzSN3u{ZBG|3P5rMQzbLo-Vo4-UQXvtOD#pBkw>R{ zYsb@p@|IuYbd$uT(k$lJ@M!O2GoIbM&J3mtNO4AV-LvWnY5ze!I|qX)S0S3-gAPa% z42RD}rHrP&g$O4TMr|`f^R~mg(6UPfuPeFEHN}Rv@P-6)lUDbx~KbD$M5w$tJz<5d1mZX{tC@4Pd* zkjYTzZ!Fnhq1kW8+7KTvI`mp9d$1^dOJC1?Qev(2klc1B-K^(1sufHQ0I416S+XRZ zddfYI4!5h1n$!9T=5ymm)_>{Ut9%d1v z@a;QwuLSYPVl?A%K-UFN>d?T&E{njt6*c&GOw-k@{HA&}6k9u8<5LrIZ^p`VLQmF{ zBH{-q;sZ0HIBymh-Nj$mEG00Z0N%kUvm)NMkanakKh4WoxF^jEd(T*%|2MV^JPNJJ z%$KvKja-dQfr{BQ(=@|R7-M5di{rlA&K$h2?g%foNWnBSB)jy8tz7Hu;Q+wRAf0nR zMlM$m<8O?l?I>&Sj|99p-GVz`9l-Tj%18~sf&|CR(tV!^yZ+?XA=d^VN4 z05_V)r9gb&6ZjhuV5sDX8*f=In!jDZEtq$JvEvGSTCwAj`QFsT&@F?RoQ+Llf@i9% z%^A5#&$C;p9=qeIbVH5~M0gkl(Rz{dLK3vq#tqlCWwWvGUS57>rtJ7N8v>wb*&+0X z`I{O5l4A&O*D#d}SsXU}*s#lRAUs5oZ2$hXjS=bQ~D%>?Yqv$~R&4W4Bsvhd(8 z+q8Io)ynL7e)k1S#6qQd<&z-DW%&|y{`S_YD)#%050+8F8s+9KiQ&~6j@1HA5_WBx zFR@ilZa8=JRi3wjkNwkD-Q2F)$WA2(H!K|+B; zLa~XKs?&sRTEVsoXdSikvVjyHWnQwpNgiVtb-^iEWbaXD=hEK9A36wPza}35kNBD% z(pR&1;-(8(A`foJsu|VTzziGSdet7h5i~@=V~YJJ6}B>C{2f}hLy~JFP*h^Y2Z#RR znjc1Bivf?`KMd8v^w=Jba@+<~r<}X2j(X8DiyZ23QWLCmL2;L*$6a>s$f7%d*$sKs zqEoQo-U&|Y*SgW2p>oTjua7G{pfBr_4`uszsyAJ??gbQ_4!qK68hY~0Gh5A18^qdm zbAQ$AGk}4lg#xIW>ZLO?TkWGoSjQ%2&|^PpRCb8D!;3}E7idqo8_52wk91;t0YuT; z-4_xghSJb;i06OmOp3}#h=)y^U3^J+Drs+HuWriFdvh-vGAJkdC+aJvQZAnjckA# z|CuvAOEPvpT!L=yNgzpV9Rm3Ngu^_yLk-VSPaEMKWf9gOC2^yOzw=K7q3ocB6{3qn z8$w&{9ECNN@(s`;CC#Lm1=A)aE1+Nr&?a?p=hMXlnBTaE!8Uu~2AxRAuKdImR&SFd z+*lu;GWk3viC>4^m?gAikz%PAns$Zd%eaQ5?|`$rXep?t+@om}Lr1 zdSsC_&mnl&Kn0BBf5&&B!v<(#+Ty{qXtgSHEcEZBKe^z#D&y@i`BekSSbbVcDu$S> z5bB5WcwuoP13;q1dIN^?41|o8W^!t&zX=(qHY3;C;WiF2RRhPjz{kT>Y()j9;dB%_ z94Zz(911hk%i1Vmo(Lae5`c;}T*5x8B(g-f$7KuAGBzd*7#iY*#KjAQjE!nKV!6H^fBsN~vLvz`EPtA8ttLV*pem z9bMI98~ww5Hr==LK3(uRw^ez!Lmi|dL9e)fng_%b2%)t)LWu5Dk-PNl5Xlizi1OOpfhcS#bZoe6amtGa}bgmo#OpfcAOC7s7=YTm3FpZZqdk43s+#VzIP2 z;9HQ`_r?rjzl2HVC|Py_`!BUzt!w?`J+lAu^aVFQkv9K88}x#VWdj0DM%KwiEw5v| z!@z0+S)U1E47!Cm-T%K-Q+>*tpZGu4^b1*i`Uzvp3mkPan(`S z)wI-1)mB}cq7G~DM$&Mi379pgO%=5=Z`fyd6}Aq4xMZdQ0OI&%h=#=>nMt+&gPr?a zoY_`GjuVo$IKzPb788u(_ygs?u+wI#RMi)D43*oQ)UOXRgWAo%(qLhCHO=QHSpH?? z8&7V&(Th*TlT})p#XxWs)nHAN6O-MqrX;5NdqVL})gr1nOvko*s%J&hAL~ zP}JP)_A-Si&WY*7J?YSk-o*wGcghAwOjqgb3D*^9CV{37b+ZO9s2W*Om=vdZ^8M6U zFujK*xoWybHdw~e`xoz&8&pWwjFs$Z&KvV?@fUb9F)P(({-R3j15x&+T)jg37F@AX zvvE&O5!D91L|qnaF+z=Ys9#7%bIehV_UG^4=mO)H_;4_W2b+uXyleREUqedBfDIeG zV}SiuYuzt*jm}79b>+MKQ^9h*Y&mWZOOgYPs9m?mg96@7HA(C*fP?N58Zvdly-i>i)m1%@W?+a5cLZ5G{>+i)0oTxg9{AL37EAi0wNNA2*>zqnR;bk! z%q~v%i1EEXY*zuE@WZfSp00Z^G1Nttr#e*K1Bm-F17T3Jg2;r~EA&8=fDz+p9p7A zN}Q5ZC3q$h|{`R0sV&S!jLj`u8FQ$)H51D7^XTsjAOp+HDe)ogy1k5QS8%r9@1VeWP1 zj{4m8e|aiWbWZ932L4<5f6F{h)x-R09Dru?pD0vAS&vk~b5i@lfm{x%-4(eyh9y5g z2HBO-oNgyfDPS^blKxoFn5oYMcdz$}$}~$)nQnG}T?ei_d7bZxGM^#aB4w*ETUR&s z_b?26G_Z-p%jSRL0kQ3Mcdi%z!UN=nZVV?%Cq24bj2!fM_zUeoN9bQexC{PufX3#J z@x?>#s3B5?557YY*3;LZO!873E^KZ zn!Q`JmS5)k0r21YBuQ$5R6c0at-A`qt-Vt)lZU#LQ_{I^uvO{j20#(a_dr0|91LiI zS2#8YL3HS_oN#d5327)f{FwoNd0-G!YNJE93A$gxAqAdV?Dgc5BL&ga7u4Wqz1OB4 zSqZ6BxvSXhZ2jY#D4IyCh4DGi&<=ZDMl*!JAoAR$b0{-k)EpK1lIQUVcDW~5yVISt~qvFE=zNY7#`KLEg$MBb~=z&%$`t{quta! zA+^4i>(~GWt>@WEy0rsKj(K2wJVH?EBAf~|xOHr|15p%cplo$es{$!VUCab-cb8zQ zqA5C8VUvuUH5!-m^^0jYECpS=29amB*XOdgx1^1-B1&72t9~|iMA~9F8!q@f&3@ytAR&I^ zH7tRp?WBq#AOF`l(GSD)FKN)j@vsyHujvARz&es9#t&!~MA;1(;^%Y=W zPpyq2IQJJesK{)<%)?ETX{5%oRQ6Fklu4cu`TpA^P!%cFoxb^o#ZBWcZ(CP3Rz_1U zt@Oo{TStH6{H7Gu6|gHGXe8fAa?v)dXJu{RaGe|B{y(lfHeMoRmefUiLd?!5DG`mf zJgf;H?cE&pQD?l{N`iL(kW~$B0G&Sizhsrj^my1VMy4ff?GH)^HT3wFhYeBjr!bji z*#i|0vQ;crMqbn&NLw&fQip^%_dO|ImLWX!c=KTXIFbl*epel93Wo@Hv=oUf(W7`O zG~5q87J!efJE=d;M#nJuk|3jT78di=lhN_f@h_^|CtQ*93a1J3WPTB(9-2bDS8WJA z%tJII7Qqx085oCVZ(or1E_)YCcgGX7OX5xRA^vwP2yphI{x`Nl~3~DW9k9Pd%g(T5du&#jTi!F z-{=Pw{7dfSLKV|hWNz~XWp0Ta&tjAJmX+UN+}say8!g+QKN+9jQ;8AhW<@(r%i89mPjg!*D%vW-`tl6e{oH{5%e|Ko>9 zR%>S}-o}MDAex=Adm$QhP?Gy_0tfzgYhUo8=2bXHa$AIWAztzF-LL*X ziTr~6*V@9?TBpt|3k2-4q5?ruJo_Kcc}GX(@3Kh(Uz39JtHz%L(5|W|I=)IJY_rs} z#ry%2OF`~K7+IU5BMVb(5rZ9JY|(T@0+c>N^u z^j#+Bw55aT@5<8eU2$XN^~__(^_+UXXmuE&x2SL}NYiU%quRT@?H5eYQnSwo!38OA zZ`}I)fEfLAVT&dRHuy*JXwtlG1OkQ}?d2D8inMkMa$82NG7P%#rmjWT4p`C65Qc1y z_N?o6Bmix)>?|pZ*1K>qC{zt{igb`M7mjjGkZfZ`tAcu=%Zo;Q!)&J3HYh;tA_V^D z>N0kO0Y$Le&bw405+fja_RdBDQf=I3v@=i&Yr289G6K0Qx%ZE8P;f|6xAg6e65ur% zo(XwK*j_{Z4eMOHi$%af4O-IL*8b^7| z!f1k&5lLj8ig^Li~{;rp@59f#;zQVVHM z4LApvui=V)Q7HDi6ve~RSs{o5Ly+bg+|FBll=JXYAe!%+Thlm;K!eT#D-}!R+5u1G zLIFwSVuAsVArrX-!@>Q5fiZ!L@Xtg(XTU$sOfDRpfmp9SWZu9dk;|SY9DFF5mzoax zyRUWVi&_X^xh0owUZp0b+=wbSM1H|xJMRhE03oAKEr%|{a>YS-tU@dbwJi>w;*7f^ z1QHqHhKRki(E1pwZIeJ$hn@^8xX-N4TAk`<(7^N$xeQBgGL;yLk89JKX2w3B_Pv=$ zes+beY9$Sa*kDE0TD9GrEwWs%8 zn3VwN##w>Enyd7-Be(Ztpd^eCZ>|Y?!)@<3!lqSL(+k?(wA)U*fGV~L)1`?Lt!!`o z21y2o83;W>jHj<~fFIl7++ZZ#?QIVkZYQQ2#GjDX{YsCVJ&WzjuOe5B07zxTY)%g+ z`T=$fT(80X&L44#qbOK$eq4rOv|gd^Y_9f9*DyTNI(N}RCz>3Ir+`fu1yI!0$D|5` zk-^!rv;6bQ5reoD)NRWznFJVknJU!WyYt8ue{cx-!Rj)sy}V}Vi5niiki#HHL@GqU z&zuwYN|cn9)1kD-uRLGV31!aH@1);KgwPbC;JFy~2_-`FDpl-t`*Tp^?ZctXn6x8s z1!~r54a^<No6hZ@a7&2Zi#&a=Oloa8!=WcM^J4BtjiD- z#uLBl;+*DBoKgCHE>rxJs6ACct7@TP-}NwJnYkEZo~kdgG~a_<@Q;M)Ri{s-39IR2 zNu_}Rg&a5PKDYq`WZS~1&L%ouP>K*0gE8TOpJ{_hp(A^DvGr_i5;}U8$^4w`@!llp zJM|C^ev=Pl$`>Xk!d{pPQMW@ublSPobNCT-{8Id@vU?c!bPR_4k+SL2%I41!qXjoo z4_a_zJ(O-{wNQW9j$X)zUOHD=Z($#`-nxb|omICiFg^LBK?D~OesXJ%1HOL;70goQM$hok+DWz+krY({S88rma;OnVUK|L z?@t?IR2vXUS|qT!2r1gf(1hfgu*3Mj>j$!z+zq58Q-}u=FXS0FipcQ7kDhZ~;0R2K zJzqW-3h*2M2JDR6eymhv;fJ3Gl3UNqVsB9vIJh7mbjh*bzT6r24#-}k6>W1Ru0~ z;jv)JLd;i0#8U!0i*skgXj%-~x1!neTs3ViHEL0#?X{?f z(>u!!9Aor(S0s7tAAExd&KJje6|kh1bGt8>xSFG*hkS2D2O4xLQWS1i%PX+ za#6G(gcL^D;|+-VStD_^A*YwYaK6s>rNt)m;-&cI!EmHvbf8!PxAvWc76@Fba-$I8 z)_%Yo0T-|Ok?fxwA*wBF2rJRB`)jZUmDT;XBi@PpEf89ntt9-;2rdFi0Gm2gbfTa_ ziIj+u5{~y&a!1$*9Z1;3kmR+EBeg^hL zV*2lUZGCDs(RmTYDm^ZF(eMlxNaCPS6q$Q=v(~Sad_Bc67KRp=w9aDT;0pc=q|*2| zpwjp-Akz5Q5Wq2*G(J$?1#<>K;mi=B{!T!t6!&^0>x%|Ju~4dY`z@IGr180u20)Ev z2r-fa>jj$n-)Q<1tu_?DH9Ubv8LG6vCDJNUeWV!Nf27=DJ^pC>UYFr%KH5iKAMK10B!|nm|2%N-5 znDB9U0?-6VZ27*E4xUU)TrA6|#KZpnNG0%KS_J>z0T_Q@wDgJq)-B_ppN9(!-(^GA z^_VZvkT=*Inhicc{K=y%t#2$A6nt%B`+)(=@dbVo@(y@x=8AHF@$OXrmtBv z*g*rQCetnf9{gU;(zJ_IJ+c1z{wF0?>CJU?A~l49k8RtC<_IqdgICpCrHuPNx*ATW z8iLtncTci}*eD5P5{zqoi@t&>O%N3$IO1z!bIs>S_0fJ>^AoL6&LjhAAIWf%d*C3^ zK)}UnfsI;WP&&Vk2Ck-iX+dqe!}U&1XEt%KtzeM5-fbW|)AuIxeD)q}+0B5!#2rKv z5WKJ`&S9otlfdR;`!H-^SL%qh>DBk&^cy6m6**4mnNjS=ch2R@ z28TVUN7QPt)s*NAt=`xG)O?&f721;Mq?cL@3|~T_<(3TpH#)@n4Oy;s*n62Mw9GnQ zj;(3C%B&|I1@&DnwvcE0wVT5p263Gmn-p3Hx^$FwRyzpRWGr9QvX;&!=@?}jOC#a_ z{yJ>#e4{l-**}AZccrx!7|-MpKWVl*`7N8rE#qI4(N|Nn`>kwkhq+)OY0Y%x1xg${ z_7xp}L;|w0*msU&uEp_?hxL{yYIe5v<{D5{IuCcnZb(_&?4wLOS92&5?U_5)GZ|J_^4o4ZX$i7t zM4?HtXvBZ}qW2BSLOYs6mSCkWw3LeD&mqbWaCaX#5AEnhl5owpd_W~W#aNoC0_p98h6BDpnQ6u79wZTPeMPtXs8XXc}V>KP`WOX39WD~jd} zCc!8OMRlC_BeRdy2jtd0H}VyKpwYF1EMG)YHUhZ9NRz{W-lPH2*9r3Q!pA8|2LN`q zZ-6^RDnTRBD?S}%|C_1@l5O z0^wv_=9}bTmYA0|l=`=E`hcaAz@$C%2=QOxZURZ?R?xL z?tdUO@AD(j4be;%yMN`=ID@PHk*QE5B{VJpQG2<}yDHp)Y zO%*Q;uq?A!c%lSmGoQcpyA>Nj1zOto4TEdztDP(D-z0k8?JfreN7-xpOK0@R2r@0J zAPUELcC6&JzaELEhbsV=o)9UJ|U$abD+oht^n| zGhA8>U00Fl`~4T9=*=oCgH&jK>j6)D2^=v`s6_E?^rGgKIL z_)9DiwHzd~mMh|PJ}Z54C$BUVEVdVnuPVRKuu%t`G?PU0m9K6CX0H5{gS2m#h;H6z?jI26!Q`Y|4v$CO6#bdxcvYs(h zVR5B7XRgeh-`Yc8&Oy?|@>FO{1oKz@Q9@PpyA1vKjXWE`Y}U_!lemiPzC^i@pm3s4 zI#DHoA)7`?Tx|~{+eu3;oGO{7p2pBtZI4klL%(qup@sbT z2w7F46mcNZIBrg`fhkTpN0wNYa=-mKeGf0JnxV_zi9&QQb@I_VFNHf80+ZHT>?Rrs zZEMD1Zb^^4vIXz!)XQ3L+Q!|iNxb%lu#4F$h^`K8m{oMV55HEP3jj~jl0tGu*p!h~ z<~vH5RZX40$=aLGLNk)2s^c^zsCSXYN}Ye=1f>#s3L^O-=WMhtM{Ewh0W=^I?8->i zY>aOf%%9+*R@MOeR?d*aKG9WEbvzX@v*$~)I3fl695ekxv-9mxK|!pu4W6Wl6NuKb zOB_DIH}dnfDe|eYHZws+H_++`;l(*0_BgbuH4BsJNH1o-YS`3U!#M*_XzYAD7-=i!YBYIvGr(*I^VenNNjztsH zQbt0Kn$+C+6IOAMCFANqNc@&S2(9FpzjU3E*>t^pRXxv8%3B(q+CrueMrB{4=WXC< z?YUiwzjifMjCShO$~M!{vsg@e4VoRuI9#Yk znZx#(0B-$DSVR}>pF^1Qx0+-g2_B}>8G}0)t3J1`PYj4IH4+A+m0ytJ`=eb@CDQ9| zuXfz1>??>suEE2!**Y$Xj_1TY;N{m>VxDY<;IhfK^toKNVbLrTaZSGKqlI7~eQF?A z*heww*&b!XjP?ZC>nA_Q&(Tve7(xsf5c%#p zTcW;@<8Qtok7EO^ zQM&up+L`f0sZu(4OK=54sp;32p?(Y9|4fkE60#AJy&$XM^`i~?}n%)wwC zxnm$akf=vooghq2{?+F&6?Iyju&5$!0n_f9;JwdlfniY(sT=oUboc0^R0^rwKjCRZ ze3uNuqW<`em=jf}_IRvfKVqxE*vlSEa&@js_UDT`nvb~wDP((D;d$`C-=6iSIOnR z#MLyohGd;WNtgn0>@aQ`&b;CWFZnE2EyA`3R{1re{-Hn7b-I-y!Nbhk_+6HJs|MXvjFuVQ=;U#t&hLbgnIq zXXCJ)T2JxpG#kcTL?6NJH30=wESuj_l>;86+iqSJwG&G*MN7VO?P#AVtkkvw0i}aK zmT`-2F!Atm zsm^+qA=&mn+4!%zI z^>*k#z#4+jJ-dU{XjP@C0Z3Zu@z%83N8jEZj;8>d?~1%`r!eYYy*<6A_&(1+34H9j zZhzhs`+hzNbiU2U2z0$|jtjiqT>HL#xUR}vNCXSo(9L&y;_xl)$MB%Gw6r{%l_R(f z(I7oxn$W^_w!9rM~!j}hFR z*bmo@1)ap4ZwKYMSd98!pZk#lKJ`vvrr%T_c?o>#BUn%1)=c;m=)LvFTbbZh3YWc} zjD9acqU+9IU&;6?QFK^B*?lhQYzbU{yz_Bx+9j2+qp#0jPSK{!YcqBJ?&s7pgImOZ zAFo2)w|7x!*HNic~0;Bjijn)Zl+Ua|AtnXfUpLa@YD*uq5;{|eWtP$l_kLu;~e^PS;p z_jgw*75dEbcspV#7i0Ah7H37v7t23JNcSDiWkaPsG8JNE-Dw`gSnMELuwZltI#$#R zU{3j<$AcBg&EV;3ARpZA`g!A_MkHQ3_Ew1o?2L1=c3hYAAaU-o;I}5V&~~9Tp>t>( z4X3k5Gzk1GyT+h$Lek;BuNK|=zoe!8O?t;zFjT<*ave{mk_EWh3&G_P$*rCjk zu$EkpT^-A#JjQuH@uTzIk;hxMF>5^R_Oz#?4!QcpPi^L!ZYuXcgj4^h+cw14|EWL4 z@d!%^4NV9Qh1szHmGmSG1$i$WV0>@rb09%wn}unF^Hbu$EDVX`xYey6$F{-6+e(8T zs(`cG^!_w|kI^0@;I=h;o8v_9aT4~aoss3b{ln;9j1XhDV`TFb??Z+lv2K@u1A`nU zM6^nDusn#|Gzc;)c(5H>9Orqs1)B6R#tK>Zf=K@m=i3#I8X-n5I(i0rs<==AMmQHS z{oV!)JMke&)P(RHzER&pfYF@8>`4jN1KA=YM=bdxFOxYlosIv4=^t4OGmUP~w07i; z(8$g1f4HA5mOeNgTEs6aFM}=TK((D}dWe9HtdLQP*t1P*>roI_HF%KbqENLrVWx(N z<*>^k$=)hX%ZB$Fx75I7SZt4UHCbn{u(Vb0-70Ym2iantc!Vov_0$-^0eLlEpw<3K z0WvU_frMLkybI^Olr~*4$IiI6x3=gA0Yg2}^PQ0BGq_{R&LWb_g9u~V_T1i_NtW-& zoKK1iA7Zf@el))5^ToNZxYppGEg^yq>={jJ)CYckL;z&zZ`l4YT^k+eLSlPLhAny%0*RvJWxw-h5lGg%sYe9q_F*Ic^wY=dM9)Tugi zPeC^$vKgPJzABJ9tv;4<1MnX6U!16 z=R~3(#0DB^mRqb&4T&!$sCH)2JF0P>s1i5f;e6qv=}UFN89(nrT$zdaorAJ9FGDsnoXZGs(so}1Ge9X8!2IVWO}S4g3N!T5o= z6*%eC8ts+OiI3q=t^;7bDq+f4WA1ay6V3sbSnoAbeO(zkK$a`)&W|cW?TvGWaz(!# z5!Sp;H-y&gJ9MTPom^G-E-$r8pi(2l&ZR%ViJt8f2=}4?Q?MFXp-c06{?htWs~AE& zXq0yl2=`T_Hs&1qntfhhf4**iINx4o`+mN5cXmAM`+hcWe?CP%5`EsU3;4cPFMhtQ zH*bG@Jo&!9^ebdnZN2>h-t8Xs@L7M~?)LfQbh~#|Am8?RJ^m!}7~}aKB;%R;Al3}` znWm*1+7zeTdsdRkbg%8*=YGQg9tASRUS4D)5t@qB=8vBdT1$3-pn{{C{-q1i z=^5JBG@Ic2R2d4HdsyZir?OrLnhudyD_&Jd2`f$qJs`ggi7Ioa#9FvH_;;b zayYJN>4#vV$4LepyB+`cdEx+(I4PbnHTr=hv<{f~9Ho6&e*e8(6e0Z(zLq4G$2As$ zOe6Guzz$)A$iO5?run+ys!gYga9wp;)NU<#3g016CBXxKfTb5O#0e zujMf^w%q8|LN%dQnU{x5EXI)O<#z=|)@OMj#`3aU65m4P<#|c<@FuMk0#CJOelVmR zN`Dk+fog=iN!5&U@2TE#m#k%>e2QGE|GRj1+1{nCnr^D0xeqs(wP%gV{8qZVdtD_y zd1n>E+h~g0NvK_zq!uhp{#ZFFnaxl=l)=ow?0viw#JsFBp*ZYwHJDDEM@f*iUFDyY zxj{S)-YPVLxCed!1q- zCHQ2PV$lG>Lt{B{XeY4j7Ls%{`O~ZMSg2``AaSeMr{3o77>&(P5!ydq?Mn-SUvt`V zXoHzZ7B-WP;28|y>|}dI%f&*nLa#iT#qzY&I_G{ARyU;I)RgsT6+Ba@_KM<}2jTHV zehFSnQ5XzcNBFuFtymMWY2VBIiYtOzQGkNnAyB%oOEJiz-E~=-W7$gI>dJJwm*!Ha zb}O{VqUjq|GgEV?0U+e3G2M0qJ?hnjxf+Z3G}0Z{IHIaNGk_C_;%@wP%_z-r&VEPZ z&4IE}cg+-Ovcs41`@P!6H%f^S7ZhIb_kI{_XGyil$Y>p|P+(kO9!`sYp5lE3#Euda zA0p`U&vE6=G;sT((~TM#L<-6Aw3aG+AmmrFcZyN-59HS#sN^RETm1ZuZM{nh`R3GE zTT}a0T32bWM}@dC3=P`L4-Fa&7*PIb&>g@lwF5BOwL=dqkmH!E066sg z$G;a1TAsq8XC)pw_;BYU=8~yoxSGJd%mCa7ZM-hOn7ID@uGIz3e3eDV3C^c4q^ZVEO`ZJi1C7}rw$92- zmpp}bt(jd%LgYcjS&DVAYtK9M$m3U44U(_<9Ik=Hv(S{6|_H>R`{j@n}{} z(gZ>5BFwH4PCh+6S__~(dI$c`qUUE_hfBoq10E*W9TN6GK)kfR#uQ6w*Asd| z#JN4uAn*UU z0C9HZeqj$&e)p&TJ;V9Ma?5L~==J(z?Wdy}JhQT3^$t2UVMI+EU?uPyz_^+o{vXsY z6^Qy7n*mY3Iw0yt7k!1AQk7Pyuo`8eKhkkS2TE^%o>PaxgOf&;HHdE9!AugVep1gC zN*Xy$pumy9HOLz|PBu;YW3(Ov_d|&V;AQKc9KcfJ9-~#^&mZm1AMW78=wj=&<&N21 z&HSAp35bPcDUg9E7CIT*!3U1#=?KX}oxmCW=fWdVocz6*!4P$P6MmeJJuB3wan9bR z|NLiyIzC*%7Xi?}SO#UK8}wgj!wpYT6c1!BBG9kFXfEP?w}67qsI}nB@Si{6`siMu zXi>S!Zwmg>x5G2cNqbKoDbly0f~qe?D%6uwh0mRS(zn@;XDCT~#maAl_CANXr5K+e ziU1#)!E3h!>02H@w@Y04z*8l_hYDbjh~{^`yoiX$@HbNr-Ty)CUq`Z5SfcfiE9b__ zgh|j|m&^(jQZ)7_u`^P;e%SY=o&(HEj0K*IXN}10g_K zg`j{lJwaO(;0&nyBWzd*2T&xOVdx`>EOQm3h@+^44r)qxNeS**xEg{)}RmwPRF$F3(WlqsZWpKGdXNp#HT2*X!1z7sCdHUshxiAj;8m zbS4@dt??R1J}50w_SaH%aPFZ&DQF|Puz%qlSYf)rgf(ivO)03FPb=q2h8 zn@>g&qV;7Sg~!tR7VNu*YX0?-w=yLG;T$tCoGzHOaE*-F5va{LP8E2$24C8D1B@Tp zLr68HNC@40l}r0&B1{{+)>VWS9ltqV8_W%|UP_nm1(uoCd|(^q8Xi_F^LnX{bsd6D z1lFQ#Bz^fDY)h`5P|#lN#qh!YVac3d6dAM_t39|_?$H<6o_qukT(BF0l)^Sv=pEVlR>Krr>DXje z2i@JWCUK>~d4K`W><}cD3v@n6Ae#Jbvw4$u0^!d5a6?VQV^Uk*fPb-|B`O8dGYAC| z1TYZ5D3IJhDUcNR1c?>*Kp^X(!2eGC(5W2^3ba)A{NTfut9IE^2`P{=rT6@5DUjjD zdsm6p4SkXf$JlMD#~&~*4$D@gN^;SiH=0l0!Lj>`?7vWt7vZ{O#b%a|>-+=s~FCe^sUbrTrI_ctk`_@G$h=kg$D$dwU6cU=M$_ zzwC?#exQn+Vi08k0&)WHq-lJsycfD7L|F_=Dq)wA29Q}vhqXFLxv(&(5{dc_&@cy^nyQcq3 z@7V+Y>b(q>u8?fm`G3{>17q`;PLFV1ofonIkGVtPe8Tfmwv$wH3<>cr?+;&8Hno z-O(|S7x^DOM~=lK2LWn2%mLIb7;smQM~(vA)fcrI01>@bp-dpU2PAcEQT~J6atzFj zz!MGJ)kh)llyFw9uteX7^OFe29%8ZSPoZ)&sW9~L%OW=Ydsj09Ck>VKu;qIZK@^{I&zXsr5z$hSj|pf<0@K%Pq~i3UU|cfOmzx`-1;Jf75d$V>;hpRt%JQA4C+u8f?#6MP zgxw|$gjdmmtEgt&7EyvI0?@cj)-4tT6^GajYTkFK(SSY`+n*WBhRRmhSe zc$duh`_X1+WoS&$7HQ_K?mf1U-*#%NtTSb>jnib%=ANA7BwAu70|6B)$5)1(RM-+= zYZFlsd4pTRFbOU-hF^KVVw#TduNd|o9qg7cb08y20RWEIu_F2Rmo@T@VfgJ1KyM4I zWDDkhO7vH=f`*@EQ8q38wD*s`-5(St7@xWf5ijBtkjQG=iI!7d`{iKE zv_et3EnH|cVVV?z^&nGCuJE+7l!_2yxp_#3^cMnmyCD$P5@6mH-+ zJy4|klgzRtt2>vcB4)(m{n*Q0y6z{oaj@weQ#*_5XE#c z(NFi^%8%ct64bbmqDlBOIlQ=QB2lrt)(@reBPj>2Ch&Tr4hQvvXl$!1=kirE(o<({ zYUsqLN>ZEf6MP&}y)3P9A^F4e^2c1OW7aO~(hs^0MIQ^7ZqhT>ndOChBXCmYk<0L} zxe_-vjK+?|5T9T6+h>RRYg3$I=~|jw*lY$=?cCi^JHikM@r|{rCxT!D%YTR82ehYF_1(^u8r~y$EIe3XjvwV2`4^T!s6Hq<4WJ4lU=bYk6Gu`#Z;W6 z%!i1dNIFmtUQQNCSInKv%J?}=bv_@^g+EvnV=4!dE zDBK)#_>p9Co*tWYD!a+3)!7Pls}|dx`Cg#v=K;ujfS63zKQFH!>-7P)`k9EYf`E(F zt_h}@+G|)Bav@v$83dvAZNr%40Cx_k#1H}mE27j1$OhiC9GaAN4{7UnbpQx?8^Fn~ z9zjx*w(y7B#YQ>b4ONdoF7A0kiF>L&(REUkP1&pB+rh!`j^I3@W`X%*41YJu2ZB~F zD$XP@Vquu=6|t2D;2}LH1KOr?mOXHOMe84s_jM!JTH(~FFsB5-F-z!|bTBJuLJb~e z>uN(9i(d@!fsaWVV;&NPwt~adPPmi@j;ylj;wy%t%jea~$A=WwV3v$HC}5ioA9G1E zge~Ez*9qwE3>3wPXb%SBlV^))?k$qUhaf9yWaB53z8X0mEr8ftyUz_iQVLU_I8M*X z?Lxq*vxoYoiF%}usCe$Hgt5Nr7I38H%9{{v${oC}_F$O6j3Ht5*E)*ToG09uYAwgx z(MUPiIZK1U#MYqG5$)}f?3to~$xB&aD`=9}ur@XlD!5D{c`1M&r_5OWaQFDFLQ27RloEDyeN%Y zu;do*IW0aZiZj-jNYRd4_984!%~*_%zX9j&?r3HdCC6EB^--B|T{XtJyf;X3*TJ^+ zpg550@xgCTVk7tbgT?j@k%|>cZnyOzoL~vJVJ4BubDt0$Cw`mF{7=$E>v?9oh!xGT z-RX%R4fVm6nh7wX=VOG_?2f5L2c+IO9Zdo;cQ2a(;nRT1Wj*?_Ko{zZE1&iK{Nl!4^ubgj8gYplr&$OdLOnh06*nNAG29y zk5#c?ezr-EIFu)OHYQ+t;qwm%{8q0clTj+SPwSZ5VQOP`6zCA zzzg!`z&E?9`78*u()maf$Pn=(&vc!I&tSV{;Wh+Xkg*)bb-d}vMzVx{1Clz3o_PU* z?2Z}r4d@comqAeuozAvoO`a^N`AJUsIua!JKnqhN9BkVy4ER{-hk zm>|1Y<(34gY+d*d6~IV|>va+W*=AUcmIS1A67&5=z!EPqjs}1jJqqw;!O>jbHjMaG zdqBLVF1QB`^0J`kuM}9E16;HPCSzc7+usH9!V-~=($F7PTJ4OKl!jVsU`Uv_0*eh= zB;rG8Bdv|hp>?&DnE%jxKO5?^=V=Kp7$C8Z7Djphq_1{@NeouPOBnp1=pUKD;-|LeVKmQ8|kgdjs+E5q&`> z%yQ41;IfI30xhA4GM<$rO_IOjTJaSnLC?U?WER=~bo9s`3*{NQ0|MDHq@!EXm#7Cv zIpG(qh93->9O1xb3RZ9vIODZ z0igX-7(`Z_PQCHsri(Z)@Q%7eDLtEpv#uv@u4VDJ1w*?$#m<0z+dQrQ*h0&8ZjMbz zoHOw5w{N*<->U|2G&8j2e}NnCFj)FF$+_wan58AiCki&aol>;edGrdPD;Ef?>0 zwqF86eryi&;+L1jsWmsIsikmTN`B2%Bq9K!`a_FsSQs7&M}bRPr(Jxwb^NetsrKrmPF{wp z@Op4CDhFFM7`p45>0`~L-_n@y)@aPF^x(dSQJ40_5QQAHAJNR5Vl$K9>UeJYqex1h zb}i5Ljsoq%r7)V>M%NpDad7Ts%+NP{hjOpw6Q6Xbv+;1=oKD2YpaJuP7cacO^>`}- zei)iBee942Zz#F>>Cdz9WI>HI8Uk-Bu3;a}BKU?hCU^PdtM1O->^`*0WcyGf0QyV$ zodFM`|0-=Nj~YvT!6CGPxT1-?9Dge*X_T55T|LzMQII7qaJ2Lu?m!KGqgksD_F@A3 za@J^O{yEta7Vxb7WuNH-QU+cHFURvW&^*C!$6faVCX z`ptFpT)f&o@ZC0jcLwc2a9n}JE*0P%KfWKQ*u(TX2R1J;-PpdSs+f>J`g8A+eSur#-38WyWa`y$Dsgh}?~FikZgrQ5V1HCo(Jx+;dE%tcun~0cs0+Y( za_~Yl7if5Y_CwR+3&;_^&R5jz^TTtZ1~7Qd3geQs%aiI#^F5XJb>3ha*{^a+KOs(+J#2z>Ks7vdO1s zAzwZQwT&|)7hI*#`BZ>44$;DUpC|NXpfC4#S?KsIcU3s7 zExjNg^jJ!yR5f|GYly z+FydN4M~?OI)@bx`n@x<_2{4h(g=doryvu)B(y10FdOqlHEK#rtK6M_PfSoYW|*=CMQ?`_bww~p&c@F-k{0Hq9MCXEL33S(SJ2i!M)0IJ68E0X!dgdvlYoR4*T~ zvhCUiCtIE(Y2iQh%-T~9`@YASf_{If;U52tWk(t8v^CSMX|sG_d@SD?KY6}d=sj{- zwJRn~Bq*+$)Oy#jPy_0K)$dOp%=;};Yf+P^$D&qpzqZlveV)gbMD(MUE6mv23MHkM?JE%WJnqTC|(IVf<7QH?8ebZ)9z>Q zTIu>zD_!7q%wLL97m9*_3{|_ee~GQpuiDY{Ym|9&$PBaw6i;YW1@XfTXeOKe0~AK3 zdZ#`@D?uAu+0|7)v;h7)F6C4zf)x2Hb`bNQE`%hwRWg%PO#mwbyVTVFIuRRN8@_2% zXT3xCl3}y6vwAljgsXbhhviE44sUi01e@_=xd(u!w_@F zV*?aT57_Ik2=1U$WY|tmhoiuspmo>UHMjKA3~Iig zqKUQzjykYK8l)K>p$;E(?AebQcThXz z6J*HRjtgw@x>-QT&WnYX<+9xj+Fz}QomtgvH~RGWLuE~tlfUC5Gcnv~`OgSmZgpWSX+a%I4o@TWY;r2HOHHT!EIhZ!2O4G`uDd(P?{J8S@OS-;Ppd zGL+DpuD7>g@#;EM=kUUC;lLx69wN7mAH!?${Sx7;Mil}W>7ov)3$YP?as;TsRRLNT zqLBj++LG$XkZIbdi)p(CGTY$cT7CAdJqOm5bUR#nPCE}i|@Zf4FMyaXU_7j99WxEBqaP?mZK9^YUMfGK-?-j!LBesK9e-dr5;HD zAYLiH-YT@-Az72+43acNW1;Kc6{W954FxM%(_9LC5nbGQFTtI^5W|A?hrtuAmpR+6 z%q_K?6At5tu8JEMN|naKoqYz^B@F%PJGH`310+p#YL`4WW$oYz|H}^lhOKVeS z=S3v0w8Ua;!EQ$Q+VD!x58UAn6fI-0r__sg^xG89NiUQags1Mlxt&VUyIo%wI_T-@ zNL^o7=okE-M@>GTk2+;vFHJUGA0Jm=k9Wb@d|DkZ++UA6KJgFljc;8(AD=eYhgVrY zIzJw#`Y^wnj`@MxO(fL3F!0~zA+yV2tDxI5i-4!!X}0gU{~O<%i(7FyNw4P&GG;wJwU68zTyBq3I8Cm3NDXWNZkq`(zgO zAM;~tW%yZ0;=0Dh)*>?;6$z`CN}nS!%_}j*r@_3x0)BJmjBN)69SFJ+)DYCR@g5y& zjYBG18dEx2svM6Z?(=JXYk`_Cw*(+T1;6V)a)zy82MKxPOE6UKYul6X0q_4H5zmF!kv>_{z+DiLz^aLru~Klfam{*T zP%3TL&TUql?e$`T*Z(hTepkBqk^e#nRl43A6Te+;dBwI(#UJ5y^#(ierb#MECL%a? zs*5O-zDym?gVVqs3bIbpkyZ!yFnl%ENB%ZX0ZylpzRr}<8}IzIE?bWAI&19JyZYt; z>btC-PkLri{C!)}yj}JIO<86edf@aDE%;xos@=>?b1@*rxqg8jfTGGl*|Fur6?cU+ zyM&&csFUnp9rmCs7R-{XpgqRPEUvb|krjJ92h+7uWm5-*@+t+v!aMVM74^3e`kW`x z_xU;I1F$&hmt!DQf0c)EUhsTc*htokjRgDnyEcr!NfIx=J#gPq!?mv!a z-i{m(#s(q08-;~HP;9k*n{QLNlV9_>3a{e?)HC$|P)f~8pSlUHbl1Op#!VJmIP0~= zSB*IrgORAtDikxp2?NJX`8!<&Me?AZi6%~`yc1m*47zZutmMQ*C?FnNK>NXrs{_I# z26OCuuh4gj?{z=gO6}5~dfpqez2zhM^-yAQ(!Trr>wU|{TijM8CzZxHhdwY(wk1Ow zrS*NXw;gHR|Hb-c37uWqTdy6VlupMsv20bjft4O_S<^M*|49#lr~kU{!`JctYP$mD ziFAFvWov()4B_j1ULN3kKYzaA`y_YZ?7aD?V2|BjX^TZaJnzYZ(9zL#uEh0Xg~D9Y z4zo?{4_x@9plfr(60( z(}R-Ml$7x`zL`2csTDzLGYw^%+lvi>Ev@nEKB3I#B&RfcA{>zh5FXdvq*1H!+j^lVBn_bd$NmJqNmDdfI8&?JjS~! z!lLo0Tn3aKY=Rh}+zto_&oJBh6cexVeffr*qa!WzqbkR@=feZ!1smVXYOE5$?aDU| zW5FDugP3W=AX5WIWMoYsVIAHh*Ki29ycC399f+}W*^{$yyT-1 zH8H~)7Y6>S!zT%c)6@7xxb%~PSJ7#C=&CJp`kLO(^3TsZs@i@NhZqnKUnctb_Eber z=wce`7CrXwx0ePss&?EcycaP)Ih{l)M=TG;aq$%e(nvRJ4D9BZu5 zZb`e2Bp|MgKdPNAX33eryx-(YWq3E)IP^F?&Q8N9(TFIq97%!$Zso2Jt?2~^P`_h1 zc_B)Ze3;R==l1iOnu+iHTZv@=aoo)x&|Je@Ll*ZTV6CA)?Y^A^z`M)b0*-tfM0V$B zA#tH`GshnsY%fnCWJ{3rG+Bf(hE_3n4_c^HPil?moyc2Gs}{p+^|pMucbLog6>QI?Pv+n>{y%g zC{DPJ7<1>X{hpj9<~XVoX$prv7UB8rz=wzjFQ|7b zBr(%Wj-!~dwi{iiU>&l~emhxRI3TV62*ZB-A z9IExvqPKZCaa^kUrz%|$XNuCfYiDVgvcMMFYi^bK8j+588@T{&N&~?iCUae99!?N3 z`%lJ+@>9yW!)3;7q!2n3t*2-cod*av`Z3Mk%UC1Cb$ z(L(bzcLs30mtgr1>0=_~MH(<~IxwHibhCl5H9vB!Qq1QSTTav%cy_MngYV3i#A%13 zn#M!ptEC5=(@V@Fe!j^c2?y>@REa^J6K}RU2&roIi8Axa>buc|O!%Q=Li42inn||V z4yjL@oSi8&>8*`Jz>wJiHI`BBiLF(X>EXHN9F98c4Hl^yEXVz&mk)nIJ9!8Y3))5e z?VhO?y2c#XWj?HdX;@?99lyoy^3IFLOjcOvaoRxJLcp!`!E*$Af&zcnE28mMnHN#^WI))8JKQk@Yg)$bxJ zGUD0WT+FJ_xyYaru8cfbf~9fA?od*OL@mh^4q5S|;!Fr$N!VqVp-Ew{k#)OHBTaFalSbV7vKmFqU-+og?`RJ#Xw$S$}z z$>zp)c_w)#EH8vBwsA*L?+_2 zNX3qf;S5fC#Zx9G${Pz>9g^m*1=#_;wqGh#gUu^PIsA{OS@New-wPK93o|y6u6&s? z+_L;}Jtd5b(Q?RzHV(>d!PopjGMXsl?%vJI1f$UGk*xNN}J8QXR$$Z^l473VR zl_j0k-Y+DS;w8NMq;YVai^(PXa-&mCvVzNn|J$i#+9YcH(?)79=o5E^VNoQLr1?o& zyOS6LAX8qE=K6l7<+7)75AGQotgu|JS|pKhnbh^gE`i;yqS?K5388hdNQvkqa5p(& z#MVmZ$0-p(4iU16HJ?t~okJ2Uy#0O)AJU%PB*#-L%jRLP_OF0`idxxC{eAsJ<|4Bi zQ@PI_?_fp~54xYIjJz2V&HZ3heu?_7)!y2}H@_ZHF2F6&dbb^72x|WCS~TkGVvZz{ zMr0N_5|+c|&qN-Y42hfakMrVaWR2R4t}GrQMRFOUhZl)dxTIK{>+;zTf=I<}A@r|~ z!6pLLwik}U_FqT9Y#}6?j=|1F2Mk{Ej}!f&NyF7GV)_=4-lCZSdr$k7wu5vuRc@sp zRjxJvv<~9JDpgf|t2o-zdZ}(`Rltg+FrPs!$}o-qpx$H}=k_4Fd74~9X<55G_8Vub z16uS<&aYzj;%TgFy0GF@Q`2JbQBO5+$jD*`gh8)4G`M?lR(*6D0rhy5oV)ZR-0W2F zHfx58<&BuYi~c&jRF2&;^EIwN$=MCFp4^m09b9%Mdx+X{p1`8ZS$#|N<{X{w#U~+m z3yngmy~1xG1}Kr%dQyV7QjS=bc?OiJ4ynm7T18g$s@F;b3Q1rVfu>`HoXi_+yOR@W zXr8M5KNWw7zsh-IG+#*>tG#G)0*eQV4~)QyPlo>~irR7$v~K=a*1x?}2pNleml4qH zH%a;>zbo%I5p^kvd6z-3>^Gf?0tTPpVDHMAB>jowpful>VykHGQkl@KwrI!Ji`CI% zZP3Si70oheOK5KJzB&4|kX-a*6}GqgO)J|))1+@c6^yQN-D>@obCj1;35fQlCO8Ha zpOsxb{4TbCToqEP)n!f+JUDH;ORMeM!}c|L(;33NQ{F7an^I5l5kZM1d1YA!0l8EHlY^y*}s!1!*l=-~Z#WJE&`AGj=W60z-^Lnmd z9jTB%p^a&WJqO1vIo>zX#jSJn)6{-bmjuchnQDs|%c*KKtidB4HSLpfU1rJwp#Q27 zgeTBg9?Ni>2Ue<^A%u|^WlYL{cI_oBRK;wHCZo1#)$|=-(K%0tjvGKZS!#%ogY*xqh=)|GQO_Kx-Zd^X~tu)?k+)sU2zp zhte8|X!(`4iW&QT33{liJC>5@pR2>;Yt5*71N91h+p6unp9808HqQW*S?043#$w{{ zgIPJg+O+^6R7p`9nO9(^g|1w(8K?99x|}|;A{EIKa5{yz4_4Y3 zbvw>Y8i0v`5?i%&9wCQirT}3EtGdS^UfmDCAZ#7zF=B}VHRTgD&mDWZ*;`VwNSyrt zZ_A-n?A?xem`0s0h@n5f;H8A%&gXd?VFAaRAFpe}hhrJg zQ5FCm=8%hf9l|^GA6r{*z)Gp@gPkNWQaRy%)Kp9n-lDa3fGt#*^^HDi)WIVdU^R5k zZw9RG0aj3L1x*P%(g9ZD0oL!Zl$9OBKkP1ibOr1#^hNRvrxemO%hZ!vl-Y4k$OGQO zEQYZ)0Y%sX==wfO##89__>94%*RXZzAiMG9zTmi=ZBntxdp0S()?SQc>ff%>a`gS_ zV`Ntz&g{lCC!VRITvA!XV1HUOxKYM^#H+b?WnNqdGt{>lc2-OiDj5Q@BxqZOP?0NG z$P+zN%2r_>A8u3S*vT2~STM%kn^RL6VS!h2vrNr_xl9@~_;6k;cU-f>H>xf@j6ZlW zE-eJa?5Tm>XEfG*HBz2tL*=$redul<&vAe>DmfVGN&3uO#!PsGcX)PX`Vfo-5j}RA znYWHR;M&m~vEPYaxFAB0gk^{L8*MzkWkYnqz3;wr*^0keP4y5TRsn17>umpwa$U5t z#B19_Tw4XoOe+#7GS-C~ax`zpJCnOw6JxUceuMn`SV02_cS`S>D~epp+|hg;c)CQ8 z$CxJmV1mHtrNTNdy=^$ex&iLk6RvN`j_*V{?-zh3mxbM};ohE8tFJv&pAKJCSiQ@0 z$Qmn{N#kuoln_2#l@>O>JviFsK~YX=zhkOLv+pZH8uerQ!S|fjlzz1biri9Du?C$9 zXvwyOA1x#b>Fle}0xq7P3qp%PicFd}!;PnUXUSc5#GZKQ6&u&t-o+LZP@h9R0qdwD z+5gaAhS?b8`Sw|;M6e<0m?Za3Ggpy-NSX~w`nE2Kdj_a0N;AgXSW#S>dI|eT#@7if z@&QoL_%{D2XuPo@2_*8?tKhvNkKOHmlsP!~QSC&eub-n1zQ$xN!Imvo06CFo$Dq;+ z-~8H`+;YNvv@{e}X<+p@gX`^BcaTiD$z($r!uLuElCp|XXxNEF?_cOmzW0JHTNjz% zm9zmy3E-wzC=p#@yI>Sr(an#F-cZqv@H?!M_OYl~B09hF7vju8LgU6%FZv|C{sj|P*s~wC`$tk}?l;0wn4pVJ~0|p=P_ZH0^ zsPwog*s`{F+s8)SKjD@Tp;)d9|BA6k=Q9AUjSWX7yDE3#g-}(yooseFNNC(+v-$z( zF+=;6t95|@YG{1HY+pp2Thhc;q48m>!u`OE;gK|T)5I5y3Is_Fw5#=vq`Nx<6!i;& z_5+b4wz?Mo6YYwoct2RD2j1q)1x@L^&jBO)mLtn!M-3}jRs`IU2rtqbhrD->&;^yP zRp_|e5WvO}Ch%ZPO2%kljN%|}$re6)=8-$IT{0)(w= z@GybLwY5zO2d=U$lO{=1J(DPOEVV16?XWllxVTDw5tj0$3%qo-ov3DcgVr{~%0B82 z2||fpZLAn2=VvHyW!DMUM5k2{F_&r|Z zb51~YPTeWEEe>qFZs)pHHfl#Mm><+N7Yc0l+TqyMH}qvxP$n>#xWkNLdWB{pD6auc zK}4AqSPaBwA`nd}(rVB#MVTM@w@cwC?CjX6Im4(|z~COv^MS_{{)}bb_++_K71BnR zs})rZ$C%X!~zNn{sgPb@Zl$FYa_AI6-b4weU|y7JqQ@V1;360gFZg zjP)_gLfvF={SoItA*Dc`!sj__q8E{}7lj$#_k35#J4rQ+D8?(D4eRJ-$29Rp>{Zcv zo)T5fYuy!CH<00|Rq!Djanfjkf6d1ny(cik7Da!e${5zdVl*}lAtH6k5EW`?1`%CM zsx>i{9XJGFOq|%t-v9Z371PH2RlF>YmID`v4$7NFH@$)|W6MB~*Hd~V?rqX2S<;Uj zD2%1;=N#5?bmDk=Y*Mqumk1c6`8d1}1($UH{b1d21Nw>rKt3}@yA&8*KG+(WeDviv zE>17ockq?xs$F2-ru%bAL(+OvBA7)3p^rGFSiCf8fmy zj>eISR!}G%0?Di2dqs}BEC0b5*v8>%o1QcnYs$nJ#e;{nH9Vq=ItN3c;iqh1<57Sc zy+5sy0Abw_D_#5Hgw0&KhT#`<%JxW<*BS{>Rikx^o;I+61p9@S~LlEV&GbWgi-tWrYO{7H+$849Zm1^bU7n2KJS zhA&ix?w^xU4f;-`DuaUQHt>dH2G-&rBw=9LYALqn4cz+L%5KS zj#)wm__^Rq3;L8wJ3PqgPj}pfq{(v_mVKw8!8Vc)s3;GZ9bSd}4C^*fsXD&R09=-$ zoejq35ZgHYW#*La`S+T!A7N8S=yULLRu7NnbzmqHfvzXdc z8vxPs6|DQ|GY&o0IrIT@4gLknN}bXgPWw|2#C{%SE88r9?a6wsDuV^T%(K3Z(y|m) z-Gh|tPBk1Vd_-X8Jab_3w`4ey2e$8?iH)PYiO7hF;7AmB)BzKUrVyW^K|iCw-%gD? z!nEGS?>+u<#|y)M&tVx~$X(cX{}H5-GNjEWZSlBHRWNY~G7^(o(jo6s`BWTAU>6d9 zgy6Vj^!FWtlxCMfZZAJ9I{>N}?)&sj$=Z~L_X?gO!#R53^ zZm@!?6jg+v+M^aZ?O>x8!+;0hVGmgEiSpWmKEaFCgvBPXxI&(~&A)G~Cy;1wT(4!E6(sp8F3`)JY#_@JKp{@VS`z%XdULH5 zEdB-t4{db>+R|F$+^8L3w7!2pt3klcDp*l)@soRdACnFL?H*~d3l7zccu5%YeH)TH z?63ZNQ!}&)%2X+zN)^=vpnZz~w6F4Cw67!Fg5ChWIj+Tb!1i~GH?fCRdD;=PE~%+B z{W&Ut;IM}V6iN(-=AleAYN^3m<^dnEex>=M6Ivb&i1J?%t9>nnu-w=gVgJMX^1c4V zDZWiJo8gEJydrUuT=K}l8YX!z1O8PF%$(7Bx`DOWUbWj6HxfuQ78XNI-j}h0X7-8G zJA}zRZyAU+a?Nkf0!!QqMeASE;r~z;EUf!pXvgb+kqqpP@&7Rhh_3M|1)aR@SB?eK zK&wFxd;*RI|NC6QdXLPcR7}!Z@Or6646ytZ<_4W(5?&8yHfgKYe-_QPD+E+Lx}^Fb z>2W*2!d&_NH)j#{)At0RPOfL1 z_P=u>%I##x1r7-hrirUhUO$MSL*ZsyaUAUlqlf)3pYgy3Jnq?O=6XYibw2gEo3dP( z)%%l^e~C{H108T#A<>}54p>x-QNy#UPGeE0**$dbm8>-O&!%5Mib3np4EYR<7l*$0 z+U|o<6{afjg3jV_^Zo)`vZ!@KOg3YzYcy}dC#lSzW%D;?PZ%$VV;4egYDPUU>bkv5 zfzFmJ(ECLW(nO+(mPV|{pBCjf(jPd8=pNEPJEvVP=q{g zK(@!a=AO{-<3tqOGWvzX+#Yo<;DI2c>KC`0%}7ifCqVnu@BfeWaKB{jeB-7q=#!1T zG*(*0lW|sSajElvhz9?W{~;Q{<_qWaZy*LnGi1)MrQOjDLUlQ@lT9x&LgL)=mKLy5 zV=DA2(X68MTjMv0JZ1fjgGM0=e^aujC;R; z>Xv&VCTt%|<}Sy9_4US;VxS{iKh?TEPBz^z9x{2INW}>p)t!$z4@D`NOwAGiWh4*$ zDEnuv0-%hgZ8d|R(9W*ieuh7!z(Nd(E=s~=yXTJ z!0G2K`61`QO6unukNX+co1w{E%i3uzfrr&Oz1HGKEUnMKhBn(+C9JVMcD)yi zw)^;0J#r6bW-f3#I2^^|Dym7Qbcij87tf4xM#`z0)j&Xfy=GoLpL}A3#>f3lh-|Y%E#IXP>>CuO;WrkV0aFjVr{N&$MkCxV>x;XDT%q-~#6T z-uKX;`+f-|4R#g5;4S`*G$1a11{~~s_&ju+ph@t8j>F45c%4q*uPuYHWkW+rIW5Rx z(nv?E1;oX4uXl>8i=@?Us2pyiJ+C?^{Rzi)W`aBL+eSO!?nZQGB0U&vqdlO^J-gLS zg}St|)^ZWDk3|qGs3#|7ciAy<0ik~@j;LCxvy4%UJ-n4pqtz~$)qat`yRpulE!=G+ zXm!&er;|d_W+(@9D#i!vfbUHUC6aY1E1UYN%A)RE#OVOD2Fdu~Wo6iTd{%^u zvSZtfp0)vLK0*;jQAGO6c(~Sr{1{}UW0xOOAiDhSpV3rH5#Kku_JdQHkMp7B(U! zmQ@)1j>|SN<%nU!>>+S#?9bEf#?apHO%ph-JB@y8VAkp1t%ReE(t=fPrVj zS;o($7s46WD9A5H-0Q+LZFZeFqB@ogw4$Pd{j0Ve2BSC(7OnY09}|?#)YRHC>zvI$ z3$eaA@fRFe!ezLbP_{PYYs|P}FFD}Qm&Ph(onTvgjEnZ3xnlOCQH8Z=RbL%#6y%3w zH`_|HLvE%hggvMdPDrT3;QZ+E@AWx>!Y{M{`U`=EJBh+(UWTyFMj?5`^PTKq7SfOY zCJ9DLo(B&j03kDeiXepi8%}V=odjC88Bd!F^nLzhleoiiIj<>t=aGk zvxWqpo;{e#mmovvKy3QnxIOL%P3mzIRG*k5`F$1diha0vX=AyfjNmIA#R8-Sc~XL$ zjE1H9MuJquD;@rUtWy^akAac(PKg3e@KNZCSVh|=ToRX(N}*2CM!56~<*$Pd(32W| z$9Qcn8yK^)K|IN_*=25@Q)v5d(ES54F=Mb&wCda~@Kg)x6|>fD4aVnRqy@ z3vx??Yv8;*n%CD7Dd}usobZ;G+e9seoX@wTAkEc^ZlY`zf z0Unhp3p-iVP|%kxhuz^Gbn6Z~S!Lb4DqvXa4xF(&S!2B27gbMMGz2M5@Ce_JGZA~r ziGAY)M@EkOW>>8Ygw?NrOxL-I^B*8`41d})y~fmMxvRHkZp18meB*kWgb3yRPJx+_ z5s^h+6T1P;^wfP4&k5rEkBmWDiniv?mew|fe_eyxx?+t(oP~$Mdk+83A4FXvI8~R; zew2x+b-;arknI8oDY}BYW+^Ti-S4gF>pO9J4=So?B@%B28ZYPdwZEN&0CZ;l$wa}4 z>Gea2qzuxCXXvE6uhyEP>SZy7CV}lK#WixSzqd;*Xid=omp)PGrwnJwl!9W*tZ)z_9v zjvsS3blR6LDXqSkxU=vM>3j0L+&^5qiY1BvQm)mAl^wCTCjDj!YdIvB2jqF3E{>G0 zv&TL2r<>+Hp1E31*9<-9FZiST8%hdjW;ST1u>OA&B%6cfaG_1|sxhwI;MydcL^o)m zO`u3N%+mxni=i-~O_xBI!v!TkD-;ySdr4r-!&^0Up8U$JUNQx!n;IxvymKg*%!$%6 zG}bJX+55NkoJw8B9U?Ca2_3R+@U{AC)^N}+CEPo0oX1P0@=};uN^98ZxJ?4rwF3i$O5HbN4$`Q-8m5{eMdoItU8j^|VQl_+kiuHFZ8vJrs;+_&=$MTDx*fIIWn)N7cgVTL)IJ#Z`*D4{%*Y& zoR&_J2%|Cv?b6U~ruwgXW`pgT$gHW)%70q6WSDS?QG>2HBU71kHAo)tpf);}E*5Jt zXG^kbFDy3^STs|b2#}yJo#KCsrXRhyoVsuPDVLTZLGQa{=0|H`*+cjt9bG*JI# z&>XpQ$i?@+;;L{k7%WsH7jjt%-?r`?ZDS;2n>7}* zWVA{f8pe;Rp=w8E9NrAd%b$qk&72~N%G&sU^tQkp)wS5f=QJ}`=r?IsJa38B=+{!U z@uTJJ-wvZLCwlNONbx zP3R4VBrTPmEUf|3-Ezr(nQ_{mB@eh1R#Q_c+O%z2H-1H9w|}vedNHda4v5d8;LCK` zc;gkw+$>yX!|~7Mop_%wCFesoG;c{AX?mo0upgv)LSitE$X-F zmF7K`v2T6cj;wX?w?X`JyiGQMIn2qWURf;n`&;|sV0#XW<0@IwwK8t8^s1_1BDHeq zgMsy0affpKnQrNnFRF6T<3;;-LC!cumiJftoTM@ghlQx&))M7b6Hx2JwGW30D1+1z zK^ck~<_IbWB4gGPtpoG0o~D<*ZIAYBk{K}5cT+JAGWWjt5~oAUehq^i3IC($V3sAq z1Ny--+qUmdaFE)*{lyR5k+5Ap2^`{acrgWc|6_Dn`tcgy3z`QkYT3Tl!~N5N*ZjAGG-U)R12$u&utyggdo2npHV~89A#78Ua%9B7PW{i^?O|OM9s>{YUqke zarjuWE)BU|4eMm#-P|IIe?^whQdQ%LE0tQzva7$cM?4kQwI4jb8R@3)OG~uv6d1Wb zzl7BM8Ku$+1Jt~P+CXuOjT9yhWaDZ=^ev`hGOnN2%sh1sfy&Ap6jv58YvE`IRarx| zlPuD;=pa(KBc%zf0t%;~Rjp>#>zNG_jS!=WYtZj!0phOO_JI!SQ1K?kZF$3zGc9+v7M*vYoEQVbbYG1_{Kmi!hl=OvDb+aqUvdZFzeoORey6pmS+sSs23#9M1{e&6J;tXK&Mx&Aq z%EL*HYG$QH>py;(n+GN??O(d93H1180=&#RWE5$LZp2{QNt_;xe6v)IY+a&@+nq-I z(_;+Z7r32_RQOX0knIpawoH^R4AUYH*TM4wG78kP3HoHJSI$qNZ&4h94u=qfIod}k z$57G&O{kIClNyQ)_Z?_LYz5|HX*5d8jbm}+Y|icL%A#e%50EX#ZJSZUS9u#I0viw( zCA2EN<(lO2n6si>n=Nr@PAOLn;)4ec)r_yv&n!+XY$^d4oq9U_xLY6bKU%&Qlc%n|6uBdA#ACWZou_|J3%&?fLBZY!~G>!|J=d38Lr zKax+g3kYdNiG3UrG2p$-WfILbO3!W8$tylumxGJsbLj?pUsZP3BVhd}%!SCjZ3#rl9^p}!gd45S zm6`;;f|A;YbfP^o%sb(YT@y z8|jO=kL2ehbLdF(K zl3}yc81%n5Zow4|Sj-yyu9_HIcM8QXWLIRXM_IrfTR1I@-XzHqbk{h*A*d839;#a| zq@d|Ly?2I94sZMa*!s$-x|(219D+j#Ec`v zta$@}&guo+KAb*PyY}AIy(;FUBc|(LU&QpnG+i!QB4EmzM{&4W7#(E1v1%jzxqDS< zyk!Abh0x=e!92wjj~)FWeC1bt*B@Cap)Be;V2zmQq!{EgK78yhif_snJ!Gx9 zeW&a`Svy$9rBD$zG3mvb)6bjl$=)-1)Doj>ZYfB-%~Ss*j{8#^)b$9}c&gQfZA?P5PsJ zl=$WK@!s7CGd+Tbx`K2@@ipld*qm$2g`kS`pF{jm2wd~#syYQrq@kWW@^#8_iQPL> zn|>}?^cpRG&Ru%dfKOQ&=OaNl=&wy-agYwJ$9)zXyUY$Co15odAIt4zr17PLx`oSU z(@G}58ViqdE~)zdqu?%pVrYCZ)hezntGYp9?S7qLWIY)!dtIKnVJ=cwWolHvL=RcA z(`>Y{SS&&}gN9(vd_{}B{fm8s(@q&D`u<|qCG@@E&!a)X3(MF7V)J07A*TGeva0N| z!joFn!7jIz5-Q!gnG1xWBjA>bCX7~YSFf5HM?oiV!9S&bpxXnJL8TuO4Jhk9V2!c{ z_WpS+*umx!nfJP1O>BILRxU%mjhN#ghwmCY@XGN4P|!5!>$k>$Bv7hyd@DF_(;$!q zL<}Pc5Of=}v2^+$F2^I8;BW8<^)X)%;-sLHrx*=wL=*=O)pO8j;8D##cOjVrr?>c6W%)4BK4w=Z_Z;G%AZLjMqc z-++v4ukinLTV(^`4HYT5g$bXC20#&>&fcbtf8TpA*AhTwwMGW0tjc~>R^%&cn`_0L zZ3=+ON)1q1tqpT@+FCNG@XFTd^DV^9M^}`O#M3e^cBn1n$+VTzW|aHo*_@O>aH@neu3Qpus@zL0DZ4V@$GjOA?RC&BsF*Vri@O3eVLp1a(G=bdGI0vvJevIXQPY<}(wAZB zFIHHiyKIkfH<~Ui%g^|v&#~eS9xKSa(|wt%+b#&PQW3y^`B_=)?3oy3O9t&Xfr8s0 zGi}eqqJI7@B%P75?p;6IBBXNu;M4wH1nJdxQnGC}+xg6{flf9%3JRYhaSvtg=-uEK zafpfA=Bctlc{ZSN`DHRGmW}*EL8^MEe!OpjrTOn?lLk6{^+`Z=ThqH+2r|=@xQlwT z*G|6>&<&bo2>&ktq)YPl!j!g4(XdVhx=ds^+;%ZtT7S<#fmvKSooAFQoHH4m8jvQn zY}8z46lb@V^aC-$KT4u#shU_UKK`_tsAe_U#`RDuTI|Yt%CQY6dfjsrLz<~u)np`| zn%wh&15L=d@T017yrL{AOT3N~HH~ZclEur*Z2qd+Fe}TM2BlhFQ7cJLEz@9}4x7!$ zT%lhizTA~LovhyPL|wfg!gEWvTYrLziA9GkI|XYghrqrJHyWdy@4_4Vt-D}=O#;R_ z#ZUWNrrxlWRvQ^Z@Q!-$-vliz2%6{0u7e%cw{to|86l3;I2PDUo~Y+YF9JxzWyfsyn%-(AlMe8TRvMJY;waF7l`KMgCEMi*3jqX8SPlU z4VRutl@-aFi^b!>OXk*Tp*>&Fi_YdL|Ln!A!U9W~^AmsB;FVW{AL!B~Sz1VO2^+fQ zbWF#apLVn_CbdS96HFVD04t_CV-4!LQAMDSy>1#vGPllM!QVHYqwfJWVSOX=(3y*L z(6o^mF%bxc40EnoRBJ-_b1FABSRpmB)vc}iy6QT+7(n6R%O&-g8=E1W;LGL0j1o>&8uDk0EsteO#C|wQ z2{xq7%ELF3$&|G!1)SxT`jua68VK+%iy`B~ctsApf`e*V#$qkRw8=b~G$%4FE(9v^ zry1?oZ{?l5ZaXipldUmm%rzG_O<*qL= z?7g|m=2m1e%Bf;ZFN|+NOiwR~kfe6fI8t7n9f1I=WiivBB6}{a8o<(_L?BsW237`z z{0tq?u*$h7);2$&ydZca4hr5EQ-=rm+8jY7{no)+nL9poPkFSMYWKcKM4>*Su_$~_ zw@1U;KBoSzMgp{e4bs?O6Ck&RIZy5AvQCNI0pn)~%~NC!d~z6g@5_-j+sUx`p_Ac5 zPuM4O_rttzYiIC=*N7NAB@#eyH$Bf?8IvX($roT7$$mOaM2RIQJ*q~0RDx1P+XEY{ zOlmoG%y;+(a6ho<;QUFMDpDNybg<+k8(?z+R|fUP>I&eHA=fW%E;&e6HMjz)`>2iIFWL|ME`7E=!6=f|#O;wql%4AWI%=f61=E#;b1@f}YiNWow{)>S zZt;kW7!Z&hPMklhS-Tgqc%h6X2m~w@RE#m@p8yhs%odLPgUUX#v@^beePJu2KX^PE zAgd0;6t;Q|!+--UZJ9i~;3Ty2npOx_N}5S8GN9HhV?BsMmR5TDh)T&vB1y?t8RHT8 zRzau0D^P0~n}}Hd{u$indFT24uSFcv(vEky(vA*}Ua6D2 zM=t5&u!h{Pc*t`XPQe*VBTb6TCkF@xc_xd*42V}6SmN-vgj{BKZyRXq?jQ_8CnQ{u z-Q;*RtWLW*m7U~VkeW`roAH54?OsZppm42Ml6n`zEs%{;jpHGSz@xrIjjb>@)wgjy zaDE`p>9fPdqIv!kKZ&cNL(RomoX@eL_%%j`n(m2>%=g{t*GYGbRNwj*V|ExW#jgGM9){j2OVtv)dpB2tf1rqcCr`}+Z5TSM)SB6aa( zouMz&g>3Jay@{~+ZJ!Yv*f+KWcl)%Yuv~1NK{zrswvbvm#(D#;B=s6wtPw75t7~;x z{cICDVF8#@w2YnE!O+cUk5YWGA*J2NcP_?Z%m;DRl{@I{3`i=dyf7`EY<)Fv#m-Q% ze5hPr)oAB}bcDu=KHOej$lM@Qw#;IN;8-Y@(ezA)FJiyIHCVQ2>9(#ldRT|hU|Yor z4SX=%_=?fs+b)r`2*a>U01@7Kn6T1+3&e|HNjr&p`aW3a^V4r+M9X)R<8sI8b)v<& z$mjKkw>1KWU&aDE2XJyuL1%y77sS<+?^9XXi<%2!E=8tV4)b^Iw;LoAY8t_PbI~po zSx3`K&JFO1sv3FC<%nbGHLUz}f;v3(+t^M>V?joO{B)>62BX}*MuH@?{B+Hben)&G zwah7HIA0XlAmCZr^?*k9xRoHb-;nh(3(LH!M4LcWDluH3T+XFvs&Dlx0ny@Dt7WJLr!q1RNFBw*-Maw@jfwu{LQJ_ zi1z_YF1Ap^()jmD)v7;F(1V8peO`3?a06h!wO5-<`?~@GZ>1p>Tm9oQxeN5whQ{k0 zy(24Eb7kd~f}1CxX5x;L?To`5kHY5zBE|z!pdEj`R8aHnI zA!oJ!@oUjPu`G+4=n`6+dvl^7%n*WICV@Aw(NZ}9htm8eK=mTve~MI;EAnQ4r2o41 zp+M>~YW2^gWgXZKL1J7HxX;%x@SFb1qI5*}#B7#%VfLQ=ljBue0%=+`O!5}nCTOCG z?yhsiDU8^<$C{H~vI`OF9K;|}&zMHl96;}`hJM6nNGo+RF*{;(|bLl@ml zyxEZOb=hpK?7-C{h{}eB&}q`LbaN~gZ-yfJOhwUbaaQ%Typ(eQyx<2q*;P}T{xk^{ z8|M$&cBYVJi_EbBfTuh+NJeF-yMmW>U9BiYWDwi8g9gWAmgOM04F2q~rXd>AMq(jO z+Q&+zZNqIN;5cpxyKIDzDFZ0k88QDvyNRf$0QLb};S&y^G{9_oasLj-{LHUC3PA)1 z7Io}Clw;NVtI)tUqSUL#_l(3;>B@jg$uvYo?jrtZQIl1|089V%{eVBL+Y0(>u3!H{1S)Xvh_XW&!m5^OKP@322g zL-urcv0DxlE^YUg}{rb&RA+N8gEEfdOkTT3c-K2>Afbb*3EU6dNZH-{HR0EaX1PL~A z0&fL5v2&lz`vBK%SwC3q^X|6E7A(USt~!4jootac%treIhku`W8$7)yn9IPP`BF%y zE7%jhmHBeJH}a#W_eW0%%+!apL8~oC1gmsWX8)wLpZYCCx*~~ns%%(=R@TyLj-pRg z6YM0phx4N&6Sx+Ei)xA*MG5h6+j2>Ch z1L9}S5Vn&web*G2P%Ma0EG#{9GIR8%(H8CoeED%oxI(-G-Q|UwGoc;%vOYZH`=y^X zQ=a;&H%m>V?uz$j>lc((AZyNQ0l>Yg{ih zAGOMEt5E8OGd@*ji(YzfplhFZ3Uu#1aON%CPNYZ!E;s;3dSoB*11CxQG391Wt)*jX zc&R+jo)3FJO^vU3&EeIGzC5`-pLWO7wql=#;Kx#)MRf=rG6-WqV8CEY-GnBlz9}Zo z%Z@#lrpN=*D%7UX3J(+)!AlSZxgQ=4CizRy1!2Fg58fpZMWIHb~o@}BK=!YCC?wZun(~a3#zK_lVN4m zG1rS-8`#Q{Bh$&H$v9^1!x}Sf@-3VK6Zts`9yI?&P;0>HcnjUC)28;N?a3LVWHQY; zW0^pAKxW%%NYL7U!{!04*_Wk+6%A=nE$<~7GR{X@136kI<1_Q7RZ)gvr09`e?L718 zc`Lp|^1O1tDj%}%OkMIcoUH{ z2+3(2_$AItK$(;PG{as-L%018@FDbNW<-zlsUEuOH28vS=A5ng5+%4o|F?rNd_GBSbRMUkxK@ zmdL<%?atG&5QTaYfXzU8^8R77XtLb^N--5V)4VqFvgYjhkGJaFEnbNLk>nb=R_s5K zgg>5?d`=Z#ZCXFCD7_j+qNoT-QPb7rGpaPTb^$D^1j_)yO17S1HKE#`=@Pbm7$Wx5$Rrz0)F1-}`FyY$Ynudzl_b;M#T{{o6Qdz_ zY-&9%NBY2*a7=;Gf(p&}WWP(p)<&jW82}}(67IT1UWBJP?ne^lTa_d^!@IUeq1PSV zG-7Jqf>Z^NO$b&4N7FQKyiTjIrBu~PY8!C*FRXPf;vAsZbHAJe$FQ`~5l}e)gG*j5 z4z|MMBM~d^7Q6`LO3sZ@)mS%F|HIRi`wV6M<7p(hby>~H(glN?QDBa>f^F#-p%_a( z{Fv|ZFRaHNw{MdaADpjMT+n61qT4uXVV#R%4k2BvY^;zyE*Zn_)p02cv`oKl>Te$Z z{^PFpNa!PlJ(_r3cJH-!RsdOvoysrG#5TZqR)R$#7cT5QiEw{|HZ9SOa(A!4h9P;bz@wZyJIefmvv&(#eB zehx{9q&7IqY-&7L_AYV0!U>Ye!mI8{}GmrwXE6)ue;+d z&klZrOv|dy$}2omE>~gta6^1KIlXK`+cUk_h8m8IV41QM3oEziYgRksXi4i2P{Ee+ zHDlL=TjWO4Z>%Uqdg+CeZKNH$S5Zd*3d>Mo#HVA}8z|U?1)s|nNNNlK^m@SgS7=re z){xNpu0YfQbl@T!n?E{m;Eu!ZGIyLM(cOL*c_k|xhU@qx=3oz}hSlymqT9z}4Pdfj zI!6StyB1_R??n?}vc$!-yM`}6azEPBC@X9pu2vy|odGjOhw%L#qC2CY$cN}D7SgHs zSl*Am`t7LM?64naeo*BdXc=%I*tfkeSSGF$-cQ-mZ8*LL?0j#=anC1?GW7H6t{&yB z9pz)yALrr?dqtDt_YDb`_4#%W*qvzCRHjY^1D(U;qj*!lr_x#&&`~)k2vLyGPrpJ8 zCr!^P>56Mn%#>r$Q60znMhl6t9-r>RnbeBPks?!twy5+TgioISv@l}dBrfeey>0s0 zk#O_Q>3k9q_G5M~8m}IDV}k^N#I#udW!Hqx?WXx0Q-y{g)*TnG(fpyrcbOO(W`)sq z!yn+Y!)i2#ZZxNz>@?rzhiC|Q^}0S#(MmAyXuk=xYyN@J9^vX$q3h_iyb!GlDpVhE zlfUccf&>>Az>P9A5=p?rF8{Y+5T=@@uAx()>Nm?tttB}gBeQ7>Uf5*5(~PudVa0`R z_nE+8+X_=@c_dnrQ_a%{?2$IURP>l)0yO&?mr%oEwU?H6Fdt(fux+kBVcl9NsOX$; z*?3BW_Mu{1A5pFF>z+ebdxm3T41vd1H_a-MlddS~yskezi7}1UXK)zk_dIg9r1C%Y zM=qPis5W7vyX^mKnc}1d!lwtMTqp??RKLklZ!~;*s4N~R32($?SiqGv0UuPjEBEJX z5jz_v>p4mN-Wa#m73^XlA1mm1ES{N^OHqO)@}yIUY0 ze~+3w@HQ#oa@b0fTZZZSwM>IUT?a8#DvYQ>cSY}(pC+X zqu8gN&RIjAQX@H?52-MNjOMFmvq{oNs6i*x7{7ExH%Hn)+xQpBb+X6z^@?#0rQ z)2zA4mJfxfDn~!P+z8l`OQ%S+;&kvyRruw*z^g=^o-7XMjRN*yZ9s1_^FL+Stt0ut z@OeU7<+i{0R{M%UEH6)kB`gYEeu%;v7oT+D*03n3eEv;1<8y#HR&sStuk30+8OP6X zU7=Jx*u%s9fZ>t$vJ~&Jub0#upJ{R{L=pw(|lTPPouFLIks?rk17m=H{p%MX`J zxbWDpo&^xjngD8=YdJto+fN3iI%~3;@OLc-xmO3MX%oBr0j`t)J5OO~d3sTl0T3ymboC<;_!=i}Gs%V&m*$!K!UXP<_PG?k3^GY+S2 zutP5|cV-rPwlP$2B~*qi1X#aRbR_~+GF0Mlg+p9)S>lSAd4!+y2ZGd8N{x4NdguLv z?9zbkn>j-z;#GO>h9O?j$x_DcURCI%JI5+@2SBY4ob19IbM`Z=(rhT+V>j4JB6lr+rTk|P7msje7!+vpjqjU zMEq^9>xbTCjOd5{HFBA>!N}PO+;Dl_5{_qLku6WFPC>OY2U4K(kI$ihVRY=Dc8OWj zt?8m)=P{tDEl*LG*bdh~Jui!^qRYZuEnZZvzf7)92UaOiU_c;lE987X;cEZdFtUw~ z;c-TzcprbtFo)%6b%*)t07EuCrrk>6Q8u&X6w5KQ%*$bHL)-?WS+HAInZwj_;zzS8 z$`-jqt#}Vaw#G&nHuraZdjmgrV{t+twqQwS{KT*StBQ7(>M$sV&ikEsPRz7b$tND{ zL)N=qnn8lg{__a}yWvyCyAG6#q}0mWTmD$o{bImTVbj)*l-#Z~a;{34SVD;T4RN<2 zcRqjbDRiy8u&x^U>;Sug>NeX*fBRuq7JZ-r;oFDk06_H5)j>h!#~k-Yiw+2)=g-yg z7Vd$i52Cjt;LFW&^~@s;elv+Hl|0bDwc@W9qlY^%C!Q{; zRjAX_MN2WYcPS8O=eho?E~pCu*pz`Ayax;EVH6B1IE7%Sf-wusHLB5}o^B5P+PO|1 zw4`|RQ3=`69Zl>B?YGP`;JmiwakwXf4U5;56gs-eHqA;BgyU;b4kLU?+^#@P_3j{2PL*Bv>Ako+uMu?=)3~V38k*C?)I7WafFz>1u-pGt;P8EernD$DKht|=XL;3 zeW?De+KHq7^4Yj2LTiS%UN^26^0%847M5&DaZ!fH{J~yYSd{_pF!W0u9vt+0b)tlX z3x9js)6<*~p6A;X37*+#`PSEXoPt3FaVGHHFpi%c->`FtN0${OR=v)?T=m@*!Ayy> zYP;+=Y}0zY%p4nItTP@NywpYazx6R}xi)Q8cDEDqG z|19`(F0oH2*6G#g$^H8JMxuS`btWsog?=&e^(n?K3-#Wlmt`S6eKF-~>@6n{)9^o^ zYr!v{Ysoixp;INx_UGN$23Jpq!yOz8=Ilv$lmlU+RPUB=$kMR_ReAf6R#=EIi$8Nb zPzopzS=F14FsWgG)>Xz|R|nV@evE9e#k(7a@dal^M@0KgWZ!+C(Yon!VumQYY78{| z(e+86c^ND@!S1*TX)hxKE&Lu=8^jX66O=#I7_dhXL7b5CZDa1YA7I+&dHs>w7On>1kqzrSwZu-luw1RAIBeJ zST#C)Tk=-gHs5v%Ab*~ZT96EFA}o|=`>@_bg$pu&1UjmH!@=F@H=0u90j)b8^XLTi=!Nz*tC-LX!%kN3| zCP==Evps8Y7N5EHPk&Hlle#IvxL-;d`nP)lzAt*jX3;2CUj{=$gMY%!&C+e}9A%Cz zg9)0?GX>^%SM`HS%LxIS9DP^-XXta@_)=WN-7w-FR@$b0c6CB#;uhP9?pf%8l$HJ@ zri4*T!Ohb)qmq^R>+1ywT;XCdWK2>f!+V1BnhhHgyw5>y zj~d1bXCER7TnN~p>ti{L0q{O>61Z(~S`+Qr3-+$ShKJo^q1e<*U4w?DXLcW(aQIR# z47P;fZKfT+Fyzx%6N*}bog-QKw^GW!IRDuKr|uBqOl6-Czdkb^0VH|YFz0Tc3|}Iq z1%?KB-LDgKBtaM;TL+OQad2GX(Y;7p`23pb(pwvx4}5{!ya7$?t0bvySzTFC8$?6l z*s42|An9;>gYRizC2XKSQ{JD4(6roM7SSTFJUbqCVwDEp-O(;=t~?v$?@ll}XE1bM z0H>X^hkwuqw$wC6o+@Y8u1h;Jru8Pd83gByRM$4~tE#3YvU|a|HS4ppb~coAl@o`; zT-?JSG%>d>GO@%0FK}mPciJ3@*kZSQ5;(e^`>H1AI=n!i@WU>T#y>q_uXwZ+yL=v} z!p^Et+P-qlywL9Mfy~<{CB-Hl6yN>LSew%mc_(>(+bxT=?|R~)eC=XE_BIP7|9ULH zD0*vpPQG3{T4u1VQiv#mX4$^?`7=l!MMiZ_x|ylyN3L*H&2Kxr8o3QyrnA$^I*R%M zDDHlQHF?_{^{`DR$3y5&C~Y4IEzBmzd)Wvvum2-e4+3)1tMZo&gYKmTuq{7=WB#N3HjEIbQCWLGZ2a2tKf)XSpShZumEVDU8ZG}`{#ehwg1p(6 z(guY29ALY?&J6t@TXTePqMT=4>rZOk?U)LT*6-2>(`|SL`7dRe^u`#UNG==#50e!7eIr zdSS#rHgE4jIY=+vh|iD%D3ka+f869?*^*t(&M?6Hd6J+SJCJ|OxyS;_EzWu|3XBF>>qcAe=@U@Ae6?x?;CLgBXnvH{KH#sx(g zY^_Q21>v#iMB=spIHt1!j%gdvzm`odcMBkp7d(7!uXm1(D`H*z##WIuh=m^>fA0X~ zB@*Oe7s}>B3>Xd>?C%|Pt^;o*0dAiL-0r{I2lBMiT;uI@E}G#+dj$R?%R^l_hH-mw z*_Q2p+E_2#m8~DiA^2I7xmmRbd#|F7p3 zRdqBR4FPy>zJ?()q5qdT6;?EzN|x3OVH50$ODQaTC~&VM5rVV1aP(x(F5-6s z*48OYNOaG9%WVP4shlewEz|n(ahx9CDg7xv-h`sA9y>7aGq-rYC1wXkdRC1;hQ?YIz=SX@R4-{RUL+o&|~z&T9EUo)nSI=4b!04=*1LLX)0 zizVyI8w_=j^Ys+Yp>>OHYYRT0#KvofxFWDNQ2KO&0|zm5E%WJRBZfIw;3nRM{f%JH zq%EjpjxxLaXQ-d)U9Ui&Mg!WE(wV?)ooiRS3)T0E_0UrChrvViE>eM&`|l7%C>y1p zy=s!kSvbbO!|Q>ap-q|!0k1%w*@E6I;d<2&5Ca?PBf#zhp-2P9MGFE%p}oFk+VZ>cW&!DCi{h#5Tw;}DYb@hPc(A8|yUQYz zQaj0NwW(8eYwNKe&2F8M9>oe-ynl&heEAS53?DPu9Q}^WaTnriZT1|su-kRlXKx-G zyAOtDP&-Fgns^_W$Pj6t&=HOH(~$6U{&Fdxpn?PxZ1@^NG1MYc=5sgp4qe5i`+;bK zyxL^DqG9?vP-fTR2?>C%l268gfJ)fvSy5hT{A1~PL)}Bc^fYdP%(>d5O*Wmb(>l zF7Y@5f~H+E>J{Uw^9+@2MnzGysqx2WnN6ef6a*nx?9)ifuA+gq$0w;pF=L2~Za}H# z%n>_2N7{x`_Cj%hYrjB-*uV1iGzmx3o1;@@n2oR%j z&E)%+HzMG9@H+Tg!I{sQZLBnbHBkOWBx;DP$n{Gk!}$R!2An#k;AsDzU)jK1m8rNu z#8&~QE&)?Dc1~yz2Rsr12t1O5%Fky2!Hbm(DK>LF5#$cgtWYBL^=d&yyG%ujZ-)zNR#AeG^6gynxfRb0tI-aNp zRhUtoW+-D5$OOMGS~z{gBa9^dhfqyE86ur$H>W9^mkiB2Qyal9cKtqL<;V6%?cJVX zEi2ZrYKw>e?CwX%V3s;I4=zg_i}8e!1biHmkl{w#GZawAhxJeV|XJiggk z2T3j0Mz__;@K@Ki+c+vA7oE9_H&QDWlgZoVlP_s+yZWggCa1Wz+lk7?4Os@hdpzp?-?TF+QZqK3R)oF<}l}wox?<2*ZrBo1L%LNN`{HDno)x z#Yk>#ath?j#jXjF%oQN1^tf7`P!wNwZQ>TehyqVcz5gqgrS^2?{*7hmCAG@3Dhvcw zq%xYincqCua*xGYrsGPlX1-Int+ke8NUD<;i#Bs6OGKRU7c8e0%9iELCu~=ufMFpi z4cF(-LWq2X$Z^rwrTESpeMxCFS9?#!T(>>@W>(-3$Vl2vB;KGHdbOy^Au;p56#K0H z7&k*j#Nct<8T_u%5l8^Fcrd#KD7q5PU@t;UU$6Pp3T&M6PLvbC%m^vMc z$1g?^C$@_(*fc9tlOfn7kAevQpJF;GI|90q2mnVO-VpzRBTO)gIyayQ7C>_s`au+; z7a;&tvH0ZhP0ErZSptueu(`b2Bz3B&9m1KZ`786UAd5HjIGYvQSaQOfrQJ(pRynzAy zXR}%XnYP~Y;~rl_0O?sgb^|A!Z%>3M5w*KFG;s$!8E)B<%@Q;JYx6m@;Mp zc62%d8<>JCoX#S4d(4NTe{>E+DZ7|bBb2`|IDdr7ceIQ3+G{zr}Ia*EHDvZ zFohi0ctCr`^5b!MlNOo`Sob!762`FpiF-LhZaG&u>mW?2OC?CI}q$2gaQKI-=zRcO=N|$i^ls4HGvQZg6^q+ z_yH851;y&UNB+u6(g4?~deSzeuKy`sFh>J3N<4>4^wDyqWXZ_hL0$cIeadCPfJIXS zT^sHR`2s=Y>KyKB3ZIC*Oi~2yPH&f7zzxHk7OLXCoOUO-!FQ1s&qFE(jJe|@9b2Z1 z%)d-d0k~@IoRyQ&tPQ{}B#?K^Wmd5}hR5jndLUcd@j->5xPmLDIF+|hUo&!@wO_X^FnrRVoZuGf=o&-as=b@!J;v<&yVz7i_V_m{bI&DUqcjCa7c zi{zSZp>PM`pPn2ms`p)9Y^Z*nio%JQ_M)F-3^OItTsI5wihI)jZKL(x6<8)C58$#S;?7eoQJ9HpSC)OA(#}@Dt1c3W z9Bh!&>UcWXp5Vfq-7xx!8d-G0OyfZvRH~Dnr|5pKzlqL(ze*{rtV-ri^-fhUr4f{m z@lM-zwrmZ~^>%pM=yMq;i20mI$mKybMnu?>zmUzM{7Qta-*SSLh4=o%Ba>U$080-jdPr`R@~;!kCLio?YbOBHKw_ah{h_ircD4s3X@LB-6{ z659b*5NEQy+`ymu?v_uBm;+7HLFheYBs%i(22E6OWXj%r$1^c+>qgEH&?$1{2nl<| z8oLQ&b$cAL;kj5Wv;wjL`$*2~Db1!-;L@F1%Ui@=0?$dgZ%20O5|Da5yx;!t267!@F{`0r@7W|wI`$;`c%f! zb!`)zFKS$|A3&pKMeK=kZPg$1=`~aJ&`b{(_Hea_2IK1hjep-x585N=#qIYFoZ}Ii z_GQsJ(LmGzYnC#hk}VRk)33&QKCYgH`Q=FQYV?vDj-e7(UA^`) zFTL1IgS8u(9aa!?s{WAfV;Hr_26c+|Rx26)DzBaBOfmhcek8bumyrFPNQB4!LUE-H zxYpI213|I35}5XU&B(;!kn1%AK-cC z4D)^Sf4dF$d%M;7bp=Oh*{U!YN?03y$$|r2?@`{XeknU6FoKZHSBc`2M=XqxuoSTF zoxm;jk=^;L$(Qz92m`d2NEvX8w$F+}K;-PnINxuPyb|sDj~U ze;~lD*ImiFM$ld9x(3exnXh*5VA2jdpXY*Lu}V*QmJab&kG)E?3zI-%#^irkRs9y( zTA>AEaugS>XdHL}^M#v;p(WI{qCpN(_#_12UYcR#$l)4onlkovdFo8F2&t=<^A zeTMExi|*v})t4c0A4y`z$XCWHvBo0!T~?u#UZ=p!ejpp8%`IQj9+6B@YF!8&zf^m) zONW%Z=EN(+Cm#!jI%4h+!h}SAaN^Z-v>DegXN%k(GBogrf9AWLs8}DZ+n-?|F1HAyoh)}BLoKX=fAr>rNOU4UG4j{>iob|*&OPM8GHL4t=M@Etr#W9feE` zY(j6ltyguoWvjP<+D$(Lp);VgSNT|JsosF-4CoisF;6|{Q6a`MbrLY=yRk4Vi^K!C zEn_0$13Np&)4=}T`j-Bob5MI{07#J2X(x@= zW{1p{H!ox>V8^BpDj|e}pbtCdq1L8K7Xds_vZDWrhlVjl3~DIDvjx&NDa(z8LwVYg zX)Pi{#J2aNT1XeBKk|qgUffUoR@g5PrYK=;n#Ob!=^6VH_b0_sV!p&dX6Zj`JIxdzsaH)M(0q;elpt2 zB@L++R>&7vQ=N%7p~?785ff*MRHhwD|3xjAbcw*()^KTFhU@|w{e;);uxB7jIC7|8 ze3sC8UZAR>!t=7f`h<_jk>q6a8ha|Y%j1N*g(4NMtpjxO8P{tqa19UGS_+k=~>q<@frWsd>~si zpA&{7frx=>dT@f7X65}Az;V{wfP+P9(}BvtV(Tr>1TM%; zDd@QPM1K>&+`USLlj^fbv_;sos{Y-h6p3E)IBq zQqhRsrsl%8Q+lqDH}y9YVKbT*E5`<>xS19^gZ0oxMmS&o;?X2pwvY|bAJG`=lB=yT(%6i2ieMc)X z-JRz1T`=j!S`d_D+p0epLE&y4J&mD-B3~(FkZHL6gZfTa(?@`bsN>t)`T6@q$LsM{ z57*niM3sm*8l0BQ zLgnYha2DMoVA7SI$g1H7V)yMVa=ZSd+YNiq2W^o^=Ao|rBjt#QojqpBi0!Sfk|Ued zzub%CF1cy)knJy=S0A6Rq`n<0A4i#1-FQgP8)8(o9;Oh_P9_IeM8g!H75BH$Qf@j7 z|7=k7W83ey0$G*4MY%7ACE2D-)xXh0c`hqGed8~^==o_`B^%)1AiTJ!v+7AK!?t=B zcp-TyH94Tr6?)UG(Y=fWis^*IPnkDl`E(3sv~9EgXs!6@2;77} z$PXz!#c+|2O~SGanwF{5WS_9ISj99zVayX&k)hNC_liz2tFpKOsD!l=UU`nqs-FOG z@Gs-=0v`JOpsC4F5|gUN_!j0MP@Q`tARvl3D*eo{%)ekvx=OVOCbU#O`Q#W7v{}Jp;C62?|8*32*S2H+ zZyTr~26X(u=tBeYil|g0bYr|^(*365QiL0Z#TN;|H^I%7b`>1H z3OL^17dndFZaH$`vY>I|LCMO>$Y2%DV zD-Z2@TpvdFUw$;r!%Dr^+^qq22{S&|ESaA!Q>wSEi!#ErzZM)ZU7U<*r-?V>Z&VT! zkA|7D*E+15wyaeZ_Kf#W@<*5~6s6zpLql*xDmm)!n%JdBj~f3HO*R!QwkSN_-tPu1 z)4`=gBp`Ea1^wNcvH~kQr70ShM|J}yT(aZ{a;|~rnPID!=%}N9Y*k8h(NdppZ(JE# zadWpq`TkUCPfGQc2iiG#`<3}UvKVL0aBAa*Ew8n5kX+ewtV zNLmXK-qOZN%iM%nVg|=iP{S(3t2$Cc2|D5WZV1-bHPc9Ss*KbjRWQuWs*)x*;82Zl z9+6{9c9nr)J1(*z$qEGIjXuiO{fsY_s=Q&5qTYVYJ4Y=1i0h$hfB|BUSSa^d8q%Bf zk?ylJ2@urmA`pl@E|51Xf)_W=#hVB%DTsaQwhv^Fs!K(%)BYyXn3h@x%@|+ZHHGJA z-QF19*A!(G53p1A1?PEMD?iOARfbo9-+Gh%>WudA$eL5rwG@hm))oYVN%Uyb90XKL zkPm78I2Wu^yq0loq?Jt;3oB||()god8Eci^sv{Q(2A8^~b@WwgRC2KXwwv$fB>e#kzTid~&`vQpw zYtU{V<+6c;|ET*JJDq?~oulozI#bI0`rO#%WGf;`tlV12ZZ+E}ZsU|TjaoBG2vjr5 z)lJz<;omM+&_$)4EHFrCDHpeNkcbKKK3%}x20D|)o8&&5^%02yz7AY7`pGZcOz{kY zqbdLa$OQLtXDOE#g;+D1nFgIjRTx-=qd% zI?y$vvspPtBn5yC#7q`m&1gKRmwFL?6uM-84mhSq$ zHeZzlJDfSb4&06hgm$aMVfK?0Rwv`bv4`?bGJ{g24i#{AXuF&%0>eRi`>uQ!k`s3>_#qTcad!NC|uEWCut`pqTQ zG@m5K5u7&I2NIm(QDS)&3v3q79Ha5gNJ_*%jATcD9?y_&0-q!jjCPzPeu)BB z@&JNUzhM%uVsGHwMnX_PCI}zT2T6s&aDr3Waj;Fi*~wY(lOs-$cCNx~(sybX=Yv|{ zO*}*(K+u3sbSMRULHbExsFoiC7pMmR&jf*;(hTjd+ybdS>*Y37yY9t~4mmzrr7{rk zDkcn;?2nwkDo<=eEKj_*#HQ4J0cLknB&7r@Pej#3J2UB zRNe&q@2T+*hV6VNn<|5yaSnHN0t&ad5(@V_LJ$;ieqfdO&kw{^eFA5+-%(8^Ute$F zAR=NvE=DWzxxSCbupR-O5>q?Pr4iaEO&+yoc%37k z9ebrl9-wbL9s@@RFPv{1{q0H`BXt!1ZhI{NeO_35F|<8kWL12S5314JB$?N>nkNp% zEDR~~zSTOQ#d5u$X)Wfu{c=Sug2ky6y{j-0M|zN%=2!qCt3!fE&?}7gLlUG92oBT) z8Ag4Ni-S|xpLOv()pEeX0>PU_xaLTQkFh?=#GN&$;z;KQhfCBb{jLKwMRbTr@fLlZ zqi})8Ru0p&BWOOrk5b2~yPk-Rb&aLC)y`_oFNvV@vBNe+F3Q$o+Tj8BJfXZS9+g!J zi|0REcyT5nzP1*dUd|;b1K>!!E8+G{T9DtAqy#@F2(N91hF+O_M5S#BQQ3L&;?G5+ zBX+YTLct(x`;)pWX%<_53>dchs}CV8e5JlVeZRj+5Mn$tWTwtEuU;F`m!j6{QJt$)YdsT&?;F+SpE@=nspiCkCEJLs=O-R5+=r~#y4zVwrecqz(}*5vDlh?RNq zy4F^;oTt%BP~T7U?oGS<4a2@s7@OMqSd1oTwAk{}F%gP;%tN2qbfP96ZT)bJn9(P# z%}96;t@+*Aq0HUzx}FZ$CVmAb<#Pv)J$yr>L;jzw0meoO*1;Hm#Y* z#Rjxn<|-Yo2=A%zeI2~^l1V7HZQXWJ#({_-Vzm!K?kHg>I{v;y{fW#}NE^W24V2^& z#+*JAdzc-5pU0wPr5lGJbP{jkilP9{ywA<6D)EhZO?AKw7dY|OjPBhsQn0$>b zkuyk{_McoChc8MU!=nJkilpxJj@c{*1g-iXLZ z?IT-X8k&NnuwA-K6bQ}HpC=GRqzu;m>pT-mGqkQ~&ljx8@bE_d>W3PU7o_wiwAHt5vj~ zBXcb6J-JV@nFa4I&>J_TE7`3b1~Q*WXqKfcClv1h>?u>7h?W3~olt=bfxaoRjZm`C zJHr=V5J?L$cAc~jA zOF0Qv*Fa-<9S^?1X*A>Y2aDujbHL8w)8PAj*m+X?Pg~+HKRDyvrpL$p%q3&dFRt$$ z&cSm`Pnre|s6~N-U%l?wP_34#uIvg|lJwO~tY!Ch4qun{O(pd8Zf0Cd-7IsO)|a}G zgU6{sTZ>J8CvAg>@!_TEBc&Kt{)O_B{UXZoe$+?&^*?^Ah)>1bX*+?iSjdridBk5# zFFp(<lt+lIMjhV!!5AB_!%4;3^R=vyJvgQk%L_N|EOQ#0H@B58uacoUdo@Ex= zhHa+UG~^8axPB{z)*zzUqw*BW0=b+fVY>VAcOqp}rAG8w&0fPmMy0}L55^=evrFvL zt=&8W@pj^AY~gU8Mm>a;@Vw5sqF{3Qs}|n{l=RQeS4hL_aJ2i0i?j~%lXQ>dH`r7w zrAzmw*V|SM*t2{~@yFt`93#Zh{a1I#jqV}J+d?&_{V}tN!rDpBnQPDf8XmCsnQ>F8 zF3HK&CR`7%sN}S}=%ybdTz=JP=0np}>}Oqf%|L3WvN^S}^~|xns_9TI`H*bMa2>gL zy;+!Li9~~$d=AcN8uEBr+g_)~Z!OX_Ws^1K!nLIRwItH@IS#Mi^zt$G*`)pS!P3c3 zJf{U8lC3Lr*&%Yf7&>0O&~>?Q7%yVDQO(OtPOlH>=*G@RT5U&Syq*m-2YiB^?Xe34 zvttyCK$41IqfS8v_Xogx0LQfYmeONVc+Qto7+v(#IPB`#;y06E*eHDR-cyBK`($1@ z_wGTciy*W4)EfRQwEld(uTW!ul=WWk(IXE#2#C%X5*6oc(lX}}u^hpB2#8*rnc}&) zfmQdFBx#9$H?6=O$RDa@qs%!|j!4aI4kuikc@RT)piX4`<`MEqY=rc{ z$i!9azW|mOJSffFw6GPIsCA9n_SlXQ%t?y}mLF#fpLEprb1ysm6n_<{qBYLjM}gsc zZaMh-%rDq4QMfMOxL$e<+8X)Rz&;dNO!*X@A2z^kd{c2y_qA3v&f~u+&9KVIMZTTK z+%7h+jKgCxl~AJIEMyWL`*TQLZ(T9Z9cQFz)8P7-m0p`_6{AJuT_z7MQHnK6=w;N^ z5UUN)b{F{#WaA? z`V{W202Ib`L|Z#UmNeVLroncuL)Z4gdZ_)a7~CXXXbCQJe%^I+qbfYa)3P=FfzPNG z5-=qhNQ_mt)u0(Fzo@8BTtxsTWz37;y`TQ*Q>?lQH}_=e&mS_L12b+uIRI-EpG(vi z@DB6TT3p9neCKJ6FQt7y)A5~Oh|hzf4MmhEu(n8{dA~>}HglR*PRj+7efA@hrEaRU zoM;sIL!luQ%^5GX=4lBP8@+HRq@I>bbrMUHC$~CUhjFwvC)1psp{`MVWaV#GQ4b&? zNJg;8kh3P&J4qt8%aV8z6@aeOu1RVZwuF-*b*b(_-7vCJppb zNj@3p%gt72*tuMO?&!s!*CweM5g1s$Ey{)CjZZW=5JUmR#@1=HFJosJdh!41VgSoq z{G2a;0w`g!vk%XG@EO?M@8ANcss$xNk8_yV_N{1XlrgxM|cI`*G;A^ z)rD4Gf~9qO=B5F~n;3p4LM8Z=BR36XqLR7lHjT7rlNxqa)i-FN@T+!+<$h!$nUK=FEo_u1}q#A&NKOk!q|WSC01O!ul^< z$%mX*`P+f22y}WwDSzIWA8$WS^=R;X>tBDYUwm!)ybL4yHdI%)_K=*7h2jmR1TJfh zKY3fHyFHrS-opByQ)IZmcj^{aD6iQJu$YfGGG2>h`DOeJocnviAGcg&lw~c)=aZ$JUu2Z3YIQwl;pF6iKum0~BJsn)3cv#&G`q79#zSnt zn0-UafwuZ=@`qgv0JL>r=&)I$mx#v(@6Ju2I=<@0axdb&o%G!ZS?2j7kHb48&40; z@acg*Y~%)&XE{O_+aXc^yK4$I`qL4kD=cpPiff^`YO5hZ9+6zb)V5s{ym>nhbm2eC zde5b++k=Dl26`XYcZAvgo$W8vcZA=pIoOY2f$Az1Be#6pC5#-MyzrkL0tj!wT*O@-UTD3tX;6ID#&TiV;bQX5B!cpwAVnw%+oMaBGGQ*)W zbLA(#$o@6?#dKefO_^%7w3ns^%Y3ofN#*zTbvayzW#WSjzs~#>6Kyp?>3lP!{rmbE zLY6PMKXK@OV*?UGvyEbr=Rnn3_MGDGI(uE-O6HAj&xPaq!42ju!Z({;O9}Sep_yq< zgmc$^8XX4(hSMw0HMB68r!uKWe7;;-^G!eUtw)q}E$Sh@vXn#m-3!RMd9@VaYt6n< zH~3l8iQ$=qKX@BCJ4HqOe#!IlFN~0wX=T{u4DE>vUoX`NyzH&P#Sfjn^G4(W4<5CLNh zJBPNG+N5S!fb-k_zoe6SwFbAWlM^2_h^{pHJ()JsgxoV><`(F)akLruYIr`aY}a*{}>znsJ&} zK>x<`sU48Wq8yT?hwss*Go`i5oAM2@Ddl+;SGMt$PLHqh;5=@E%^O1B--(Wg@_RsN zOa^{!!Q-DayGCR@I7$YHLu*&=izt-F(_&t|=1_`+2+no?Twub^ZI6ZhL+@VOZcF^b zKjsi}7bz9OLE9q(PNjq5h_b2X$cwe#J+){P}SVtqm$8h|{*Jj%uu zN!qQUJ^{EtTJq3OU4VQr8nLH6pz8QQmrp@@ytDSW8q>^`*}|wj$?oTA4O4n!B3LwD z6O&!X^Hj@vm(Sgqsk01bK1Ey7=J)j0GT*Qxsps3OKe+KV!9})ZCc*gKW~Zzr)o4+I z*}drMI}^_`u)3MMiIyG}XgS4c?&mgRdu7i^Euv{*bk-QAe-^e;2_2h{ye|;rL{qU-e@$#QM$yZ!c-K@Z8_(|8 zZQMIn?a>k~mpw2G%;r_i^wvj=QoZepLc{aoV5vM^jgpBQ__4&vs$tv|*1><+VR9lQ zSRwtOAXcBs!yVdl6+uKOCR$ z3qJfqp59;e`uUom4daO_upXc+@~SXsb!EdH*BLUXt7lgFpc-++i_Fd54X2;!^oAfq zf*%wHC_}Dn!JG=J+`a;Gk4O32TOtd4;l40`Go^ChuP_DIz7~`& zVJ-o@ST$E}1P|GcA?7)&UaO%y&AC`}X*Fg|pO+G- zCS!lAc~^PC>*<-83&$}l-#Vyn)?bCP*A2^`6Dm%5$a|tHWt{5GE%?JxPH@7&aYE$~ z!$d^A%uqolNW6W_Q1QLDv3RsJadz}v>MpQL^Iq9-=T@$U|87~(W3$ALrjnzr7x-|L zSD=a5`MOi}iKBNKmwJi`2`5F62?;^#K}G~RC&eD8F$w2UqKQ~`Uqhizz5ZV>)+OLdr=64aPl9r8xA>>^&>aX+>wT56vU_Y1h2=^ShdnWu@j1gZxK&56+#jz)C_A z|0u~a`AW1HNJ7shTy@}N^Rvkz$vjFV-n=yKU&WHs$1IQL^{jf}l9+roK(}HELmb*w zf@t-jwR{_r*D>M{hVyonl4YpupHxkVH#g7}FZ(m#Xi=1 z@QwGlXYAu~T1^~3`mYf|Kb zCVz>2^wfRrD}3YlelFK_zYPzbe1F_47<>*#?|r`-7<@mT``3IA=XZa-Rn>jn?(WCu z*KK{N_yMg(D$b8G`QF*f#5dL*`HZBLk&|tZZ!pVZO?`nBu8r({Wtr$@RluD=(1ciU!WvF7(t|Uw`n7temg85<E~Y72v=X-&+&oVT9CtpE;E4YLkFJxchU@kkav(UjuhCfPxPpDZFjtz95c2 z8^~0Izz2gQcW&!oTk75CF{v|?t-tj8=qxyVO%c;t1G5U)1gB9QjtI77$0g%IIIodL*9K6`@ zGIf@tYs<-4PMSsqMQ+q0^IN)bJW^Ha=g$2^K<+76%iIEqJKHHM`zjHc1oCh=)pM(= zP!yi#h3V-oUoeFfDLHH88#Dqcjh2!sY$Gp>LjsbRMTSYp6&mz{2uKbwq>M8Wmtgr+ z{06^M<3U<0`)x4baCk!M6w_%Q7+yo@$!fQ8fN>l3X+18CsfYy|z&1th@wHreL#U zxKDTInSWY}>4F5@4&#SBIc@5lXVIj2GG)}b1v`<+V6CfLO_NQo-g%4R@*Bj3_BLq8 zQaDzo-npFNvKQ>sK9n&nphW?o)>;KABQg5$_7WKi`_;6L1e z6|Qf&h5lB|XjG!zb&hjG87xN9G3JT^rgrsdK5jEVN_~1cdQVOtEhq-1!r?bv-wS^G zm6l-=oT3xth{@c9ZcrpH+EpC8(!ez;*deWmJ)|hIw}8eMM_FNVcq0^!UIahpugP3V zrAq`gd6ezy1E^#r_>7o0OX0c48E;GCu~;X>bZ%FNYhQKcW}r;6x2v)8P-#OLdpk1J zNbjP2ZBl^|QE+M;f~H_cF3oKeo}|o9rO5s( zT-R2!35_Se2>9C0IFDKxv1)_nq*^McV(7(*larz;l@wpG2jP*IbT-eI;uh~RlzPM^ z;4^^E2xb|w}jF~JwuOioWQwD+Yiv1kva^;X(ad#A`CxeE5C0UrB)xL-TYpV zna9~v1_ON8R*XV>XWbZh3)#khz%kNgnimvp|l}+VMj|*yKnF{jtHw9=C>H!qsKQ8X}`Z6 z)xsj9xr}}{f+>9|<*+Oimle(4iE3-iwF5*@4+Ef?&X zKTnD-oS+S^M z?!zdzFUwh4363Fym~BN2QJPV(=%djj4&IfU`WlU!x!+JSRLgakZyE-xwkoB*HPQnZu!TbmERfmYU zmjxS*rT|$S5lwSrJj*)}Vt&94l8z?S06kG`KRXC1)=2^C1LrT4Kvc#@zDR`pZTuXR zH)@ap#-G67=C*=pgQ%XZ%^0J7NW!vcWVgV7M9j}Pm@qEGv`G_|qNa!5mASF`LY98q z^Xo@iDj4^Nh+bONW#u2e>b|Sj^59$sKWs;y&||c{W`8Za$4Jtb`-nT@JxEZJIE-9 z7DY_-w*!IMH(P7Bp>%XSP(>IvXAh4dKUtj&$}6Spe{}KEPCxn4LMym|bjL5YqpyO( zD0=b}{2(xji3FB4Pb`6$wm(ug=ESp*gh)d*MEkb{xvphf5sAw&HJ1v> zUnRUN3IsP4_bca;!_=tyuA)0y?ogSKn@l;N88a-A;c&*BVdKGJO}rOYTr%8WJUbOK>oY#G+GrY z)3|m&vU!zs`Ky4jY5xQ37ut2;9ZMVla3@%4;r}~wp=}S+v83ZbP)p`kQ`cMjcvUu9 z`zT#+)7AZ0aJYL5L*-WU%&G7YhgE-ucwplF{|ngX&TUwgNYJO!$gz4vmib_1lYphK zfIMZhGG&+?gZnodD6C(6gMRs#om>V`8DAfdeIL0%V-Hu-dAf@gy99}27EXg(I#VjE zc8H`V|K*_N>Niydr6}UhN^s$OAkdC*D%uz*k;mWg&QC?77o>>n?qIPlK*{LW!5szr zEVh01T`4SN8Q0Hl`=KGOkm6q=h5YM^j5|pR87_!WC8V54Y{0~gi2?Fl$5?_TnS(}Y z#kc6{cg!omuDYQwbs2fuwIbp%T73>(ERL-p3mYGOx@bRK*qeClxKY6Ba;pODBG@&+ z3pws7ltRH^oiKJv35}}SQjqqp3VeZ8bbuiuG+#Aq`#Z=J@((qe z#0j1I?;_y7ZlezI{RSb< z9)w!6pNthfMv;X5Qmo+aZ47Jyj{OB%uHkM1K`l-&8c@0Q(Eyy^{};{|{Tt^oV32!x zC4u~OC!m{B$s-E=eic%ul)qm}6XE0@2fv+^K*6&yycR`-axy$+FqW}lxu+Ci=Z;cy z*Iut^IpKx~W5fA#nGub}s=>aXG0}Zde|(rTS!=~UKJkm_zadg6b8OsSkkh!43xl8K z{%EDi?N-_<4kUwtYaI&iIkxyynZ`^*@>?5EW*P>f4r~{4bU4)c6P}yn- z=t?TSGb$#4zWZD>dlzL6-)@}G@1y7Hd5^2x>N)LJ5tsxO0=MpNM!hF%3mXZDr&+~q zHEE{#kYh<=O&C5Pr7*~Ir6PE?08Oo|x!+63CZBw0lQA<5naQjLDUL2;5rAx(gu;9w zChcOyN%ciS!9qTDDJ&&4djcll2i`SntIvqh5!BAJ0ShyoF%dcmlp_bBtZiaB=P+HQ zYN#e*$~(ZgiQj<;2@N5bk7rg&_zSs%kXfBcF?+@TAcDCg{UWKZIGt|zca;)g&lF}6x;{*VJ-@5-d!1LMu2jI;*|33kqVd(!3@H=(l$4+YoV8=&p)yI-!qH;uD5g*a? zidc;EOL{z!urXx-$4YWMrgTCI%NP%xBFMF6^Y;s)t!>u8dtnJ9G$7AeNm3-j?zBV= zY9Yv48Mkyna9YUn2PAZ>Ey>t3vC2XUKIp)sbtDUod^EelGGXWiJPJ}EsKjx54jhj4 z$$y;lY3Y^JLoV@C4Q9ElNJ6G})Nu}LQB`EzaIt>4yhh(qMICl?_RTMCMOG##V< zUnd9$aOYKNTabUi{0#u+zflqaNUuiBwjymx+W-SdWCJ|G>2NqW!Lh}<&&AlJ7C@Bi z)6PYleJuqXd{4UEbP3x%D=kzrlFvo11J6YenOT;@e}Vu)pXY+e;oA%?;41)@J{HjS zJrQ-|dsCO-yu_oCMk zz*S#@-6tFos6Kk@Cb#sV=&e+;xV0%&x;%cE-*lj@woLzKPMEMv+KlDNe@3MRBa$iWGDq z9cFLjH@jV{f;{zc3wA+CybC9n)m_GmA5%r)FCA(Clx%Vtmd$^mzb=BDVHX-<{_R(w znY{L=K1)L+`9ReKYUk(P9Q-w{l8HnjF{jpRNVaQD9QD9!Lf$yv7pD=~sbW=qeG!mk z%H4W5CkR)e!qPT%gAOvv(=EVuSi<84q#<>Htl3;B!87{z%Ie2X8Nx0X)dz&Huk*3dzBRw0%Oek2Q$& zi18YNfIRW{WSpMHhxpuq&xz=p-$`${X)nZXC#R&Ev}F#VGxIYW+RVB=1?*GA??ZH3 z!j!LgTfK8n0<~jIj?9!3>S;t#+kr5diX^+Ow1Ji`dGQ-X=_G6~tq1WW{JVcvOuBRC z3^$bG%v~tTPBc4AEJp1Nq0E>*LK6e2IMnHPRC?=Qj!*Bi`^wGOm)76mJdptg1Dg)h zP3h$;sZi+U?rR&BE^p$V$q-3YOb0t%73G%?+as#Oc~brnVw!GV@X(_2-qpk_$bttvp*P=dJM61jIs7qNo2-sV6@Vj(eg?4g>c6I6C7@z|lPi_8ZN zc>`u7HJ3TZ9OxH*DO2IFoocGpPB^E{2V>I_Gj;mpA4S;s@(ZN%4ou$pW%82+g#C@P zaC^MBv3C6rF_T#Ri6qn-koHltBDB!$3=BCad_eMv;$R9Ssk_h=ngrKiLj-44r@B+7 zQTLBVgE%a5zrGoVDZvfxj7>=dzw>3G-zg>Gb;|{WRCoH{;}tNB23~IUU2|j$!7lHu zoZ!kLC!6R3xr*f}LR}s=;8QTuozNqDwg$W+f<*G4mTQOar}yLu5p;-pEBXMLO`~ zB~Q0V-hz8}KKy(lAcoP^IyZ5QcBha7LGl2e?5owXStu<-1{0m*(2)LzfX7T@G*sy( z2@wXy_((3CwgV#Zc|^tuTE>frLewc6eVBI59frd^ft@ADVoZjssLn=QT1x_q0KM5v z?;=P%C;sQ?-jrFG!TM#ppP=X{QCs#|G;VvwjqaAgc0az5|1E;a@HwM%YB%+RZodHnVy(Ix*?!?Xtoia_;snx3vdtax-IQV)h`f zG>bXTQ21K{0Dm4ztsLwUL&e2sc9HXJ9pzGbE&2Bde5caWZ-uBhQ#O^;hoZQ5%5%+C z9a~R|JHZ}5ukCkE5661yMUZENe1^!Jt(tyxZ4&XXeegbWbPAS+mo@v5b!aw|x>K~p zon?hi&2T0zaZ6~HWK0oX5YWK-PMEXkZF-w_mCs9vB_p>izXXi(i``U`>4fPeDgrx^GYX2*%GeLPWQ&k zpr2vM{WO>D_MGV*4! z{t-g|1NOY9Su43O6dMdq=F`r+rwSO0%IpJdPQDq|FwY|bBr#Yijs>KuoErlArzz!6 zV1bG@VYPXQXruNU^5~6Zq-Oj`4PIai){Nj=_Yx(lKWsCMs1--~MtS6O@ORy(csVg8 z$(qCpY4d3}#pV$hl+ni$X<^J#;A9qM;8lLa*w(p6<@60?i8hTSD5as86fAG>H+o>_ z1uF>?@{nZ$V;H=gdf;?dF{(JpI7#~IunYJd?3eCbVWxjr=5y%gQ-Zyh?oZ4hrX%c@ z!zd!9gth3jvOxa+*3+%xJ&V1%K*s0t5#^94bfkG2F?rbeK;8}4riSZf$y9$DF!jPS z#aY-Ov6;Led4Phd5Ne7B;!$zA!6uh%@ai}TsSrL}eqh43*2~rdyZRX!*G;+5R4+En zAI2`+yo~bVFgRQz)#Bua>|^QP0Fc`tHvFDqXjh};-iZ{+)79g_ubvl|XTH|DAhndr z56i^&qF4ziM+oQd)j+jMeA;T51QPirlG2vtu}z2PNTZSD{Fz`zYgM}Q^||eTRK4%J zu}Qtbvo>w4cXLM)_`VHeG&u^^9m`hQ?H#ESMR=^bhR<7O8e<}ZmqEtee#ybXmnOd! zDBWH?^!B*CrII>J%SUg$qGN_%TzlQGryKQ?buwizZ5V>%M+ZI$fx(>ml4sY({6ZpV(Lakc(#EWnsm?_GlAE!H- zC0?-FeNxC@tLk!y8jsAyR|M@}IZ&kT543nXAr(Tvl+H5+TcLLt<$qjBNUd5dTA`|h zJH$9nKU{Vx@5%U5q)$>pI`mtIVhBs}#;pV`l*_MZHj z`NGH@jrq0rt^=0VNi(aqTQ%I}x|hV;N1{pYMH8wq1}F#cxm_;*ESlvh0@xdtt$Hy6@Da@N&K9ZcM4rbXw;4?+9|IqKn92Off5-1aoEs* zlxv493FeSbO`0C!0G}xDm>T?h1sSl(f$)LUV-N0y#|`iQ zt#Z)>EkRIXZCF{2`^zmTShbXDFqcjCCnQx_i=dbYYIuQaAl36+htMm&uVYc$DLaTq zd5pen6pv?$jt7;GOoZc)wSA7ALVJ=C^X+P{Q}0IST$(a?%BCyQc^tsT;m7QT;g%ZL zok%FET~#(d)hvcL#ZPsKA?MJB%dpW2Js8t#gE})cgYcYKQ;=(auG-+AO@Ys-+lZK| zYkAU;?v4JR%&cod&1|aMCvB>qnB9hsZGHDB=}Q#$DxS$ZF0+-9R<_yjue>U! zsk3HU+$VaWnsU!D6^AoJUiAoX{=YNT6Z{jBf0Ao=`S&D}e$hvxA(X($C8Npx(so(vjQFDCPk-(y zbs|J*Z*OI(7tuSk&LNv%Ctxmp$&JpMQ)oo2@jIg!84ySG4A&RVu z7T7}QdeK@Bl@D(P>2rB3*x@;vw!GCwty!aNekLLNfu;@Ku2#`{7kt$@+}O^^ZuOc9 zIbS9W-%cOuxwa&0n(G$VXf>T4v%G4pFB(eTCpww>O)75W+L(Y{yr8ROtbPK0;O~}l z8i^Pmvh7?iOA$0$T$HaPimz5JS+pc6wq-VlcXGlbTL_t>KAOUbRU%DIy_({qAtg6> zezA*np+8;GDob*0K1l?cw~jt|2*0U=1?+b?gu;uvW`ffC!DnCy33!AfG)~?;V$*h z)@S;M`7~(#8v3ol_vayI%#@KS&SY_@E5Hn(rn+cG8x%cn>s)vV`-@TnuU z*!(Hktozeoa1Ldx34p>_x6|vj@#T7Oa4`AX@A+z$Cn&*SlIFFIPl z|9i8Qu?GoLgii2hE}MZaSp4I|zC2jb?8$iUUc9h5%oTodDA()Wlm9xVw13mf(|CUu z4TJOf!^eD-#CC77hn8BI!IeJ2mEM~ex2rfMbjB>&9HtEVHHC&0TX3ox1$eqDygb#Sh#}e(hGA(PE#^x{sCf)Y=<{S@%H! z#+ElkZ~r%`RpnkYsh_5IrduVtDyM7;#hxFnjG^_3`qHCvs`Gb9IyDl^ZL_4{{?y)+ zhswS(94hgB;^OGHDgMaUH4dyu<5L>P^9CBq4+1sv(TbS2g=poBV*tUuF2l?DrvIA2 za30)~Gk*^->4T}W!$RESiK!>s!Qy`DyM^p)(_kyd&Oz&;u{djn{m%+lh|}|`=N@18 z&y)Of`KxyBGIoihuM*)-(=bF|nlnOQG(lR^|oHL0$aGXLx*@x`p8nsz^Tvd=nPR8!57>IZA)HFbOvmRRjaW$?kUF7EUY^a!4IC zFXHc<<_hBmT}~yp_^(#+#3wF$$++WtiE4Yft9u~uoJ|go{?M+o&!FFWOP0+FlQkz) z&JAXz(Qb_Hw$ddwXn(%p^|sG8ctD&)T$cDN2LiB5tiI_Izr%TK8?7?QD*)&L2&e}} zC27l1-|3rbRjw78-;zy*a(5&gKwQOCZeOM;-0KYW%i|tb*vSYz_BhA5;CK%q?K80G zG%wO~E57}BUIs=ijJqwhbZ%qMaNq`B|dB$ z%OzAAOmF@u&CsD7R`D}=4XA`5R7~9gtsM5e1wNb)K&0B8R^Pe^S%dI@I^EjU1lyw2 zf1O>iY1!w!@;z~H)=yzr0O^jaf~*2hHEj7c?Af5bGas-R#1M}!s+}j1B84yEd2p%5 zo=fp2PSJC~FuqBd0ha)mdSZD39E}$;cE<+8!v-tM3_?GPUDS&ER$46=CSVgEf*ZNA(GZXqU5-!;F2e&EQYevJd&V0e;MqREZ~id@Apl_ zI{i zH=P-7JP$xbNNQ9P!L4q7Y){T9;%)LSV4&L1504?Bq=vcf08|U~O{jmn6_{vW=9&#C zsko&mcxNk=Uls{F#GO0U>1YotE-=){m{{A?TwK0T@1F_-DV{d9WyZw$q?oK;6t1Hj1ckNy*A11=o4p6C_g%; zUmGo-T=N$tWAD+L2E9f>GKOHOr5hz$%MqwS+q!sAvVvo~O+GobETr&K?U}agNI$7? zotqj0R(_BoG=a^urP@4Q*9p+g3(mI6Qk*JoabH_t`xbzpIS|gqg1$(Y3qQ%TRg? zT*ZmctMDL=&{Rfcy4~^ftK}jXIQw*=zg!A==w*ekC2)pq*MWr`7>k2=c}Ln|U~%1&CEYKq(ml=T1w>Ci%9IhQJv!;Rqg&UE8hkrFQq4p&{CS z{focb@>9&4(EsPB*e5SvIZrE7BjQq@PjfSs#F7;%n%ZLH;$S{5&XW8O4tCw;rP|-t z9TEeHIl^jAF%tJYc0X;3I9THU(we>{4l(y}th(5PS-uWE0X97syBPW3L_ z=&sAr4{QC19d=B^v(VxSeS^Z#l7O~Lj4CK#1Qr`R!>sW@Fb_-YVLhfPCW1V3{>4v7 zq|gT`*;4Enl7uu0W8^#uUesR*GEv;zx~{Lmk?dCo*>!&TO(o>=%aMN z02zSg6a8<1Miv6NN(%vmn0*$KwEt;2GRuUg5vtKt5yF6l(to=HnT5T_!ws25etW58 zz?m;yVuuDRmeh$a9Yl6icJ$zC-LxgK!Y*32B7U}hUriOQ+g0UqbPsIx{rSj26juts z!F-yd#NjFPIr;_@Gbh&MX!$vo;85BaJg`s~<8nsiy1!?Ug1|}9WW^gddXOH)SG4_Nx09GL|7-C)BO=z_rwx$7qbxdjI#3SW2V~k(a=b!<=ki>_2Bb zL$V@EPpp<3WfSg=eZ(80qyN*^xyLi1{&8Hc9V9wL5@O;IErc<*I_QRKbEinT&8W#O z%VoM)8bdlbMj+;SP2ILQ5a$dqYpxh$8NvoZGD`Q_I?KhOWq>-GJ-UhnVc`+c6* z^ZGtxh2sUC^qs=HXP^PcyGa#s@+SDc@$?{L=v=1J2V(aMy3lD(UqPNbW>bo59YX1(GnR>mAJkn9;vKXEa)j)0drNSxr8z{ z#Vb=15Z=mVW|A*zWa3;c+!?e6_#}PvVoUq*hwbMq+~U1Al%q?>f+MpYb+jw7z|9}i zNQEz$Rj^M8Bm;W^)+v@*?EJS9{`!MCyus8I+;@r$x*bORC{AbQkiiFJ zo~LXQN`R}bd00w4UHjprM`jnGA!Uf(HGg?b5Kwn-m0*@|>XFg(882}?2>yS&Ybh#<`eETB<#HJeTF zLWo%YiO|rlgji+urcmKqnCEg|b#ej&R!ySa^CLyv^D~XbowS36L)y*yGkImFeVKJ8 zmVKM&r>A(%8u!CW%+&X{P{sxKC^(!XrOF$v*-oE9AvxsgVwqm4E#7wkD=euNiqm$Y zUQ}mtR#KMR&08~7Gw1D&zizf3vzIUJR}RGz6|(Wl;W`mbB03RME0*pn5n|v!nX zeR!gZ|MT348e$NO=xVg8jTa=*S9F8UO%bUk3WlW*84{}#0)`~OFmg#2!8gQ5*YinRX zv6!mT&0HL^I^Y{=u0uPboc{uM3)`WIOJbZH(mjzSTar1NGpQ~99&Q#C$*JsX6phh_ zT`UVc=18d?d^G{|3N4>^>a6Im^is)49YCeJMSJ255TX=~ly)2R2Ss7gHCnpw_C%jJ zHW}$!YL#Yq>e7qDF@$sXW#N4aK&glBei{3BIu+R<9(4f4x z7oK|vBE`(d*1tg}0(?uhJsqR^{8c6|$bHA9P~uIQPzi371T*Y*ZkxR{pl{L=J}%;> zyY?BlJpo#Zcjx3BKI&E!99T)R0IKB*snu~_3WzXWOyO3BWBj%?uhZ>{m^b?^e5<4ph|D#s2A&G zz;4nT84;+m13E?o19GxJtzul88_zB+%62h48bg*T3sefsE81Edyd0>oZ(|)|#Q#i{ zC~^5iOS(0rmzJ<@?HL}Se)cr|QZv+{ataw&}vd22^#;RHu zKvaMXfkK{<^?t_MrA=*miw4rJKAEX5KJvpv$X#VwH^79hvd2|feg7bBUkMiQp?H^y z9mdB>^kLu_emUGepuiF4ABj>>Pb7sQ~Bs4tEN5^quy?%8}4&JAm zS!_iaWUk+2oYeC~!>FD)YE}I!fr+1;&nU)YZZTkQnG71Aq~rH+Vz+6ioIyD6&F6mw zNbuqRUx0wc9s>9z_YlB`|DES_sHSV*lq@5wu9wXI1JJ-xjeL5>0 z##L)M{ck4GC(9h2IpZ-gY%3d}F6MZs?f2TmEN=bo;xFUcW8)(=_*U3CMJ?AbE2ov zDc zVQyr3R8em|NM&qo0PMZ{avL|&DE|Gsd6^jF)(YQ6b8{G|#lWfIa)%_$QS^Z)8yyRCBP{vZh_36oe-mWW{sp%6y6%dFkYrX{ zDJ6VHrGOs9G|4_ZTGo%0vpJ23=uGB(hz$5(gp+?`8pbS(0?L9g&V(d<9J8zLygwom z_iKUKNh$Pp5cGSdw}YVHZ|*H8F~NeEAuUaCZ4J3d)zE0{I+C%twpd0xA)BQvA&GQ- ztS^}g$qAn2J=g>6TR5dZ*-!I93#aK%r4kVlA*ZQ?Z)QCpmJ*I7<7mt{`e!yGJRy<@ zG{S;Jh$ZMnoRLIE2q%&Gdqic>nld#6Qz=t1?CKR{r)EOsG#dq!wP>iC8q=5zyIm{< zk)j*32@~DY*ac!fXqnHRJ85$9kDjFFfnn;Eg zEaOO$SsG(WM9^w+0wm*zW$KLRw_0?DCq!`~oTN-p$@s#NzV3{2&NzuWKB?+ds1ZUE zPuvNCP@2W@F^g%q7^0WsH%uOLB1j@zEt1TK=>0FPIg7Iy5#Hag6-N3)i+qqAAMy!s zNFCH6iRxb`CO9IzLt+vtlJ`{djA;Civp7B_Atx5X4(fE!AyR}K(FCP24hdpoB&P%c zP1RXy>@RSd4lhuQMVvS@@r~8BV(Enj`sW}38Kc1Z(qnHXw5|lDE#Mx{_c%T*p z<8p|;?S0#8+0v(k&uK_dq^suj(92`^7TRA! z^oAt_zU`nxZ+IlDfeq!#qoeD-g7vVZnqDw^JoyNRZXAwa#E|-CD z210sSM?(Y)8LEqvgmk>9)SKZX!*RUOg>>ej&U*vQN(d9wYRy=p_ApH*!+hLc>yJaz zwH!x`jyanVIVG8Jb8e@`)Ix0ZD+y%)l^x1v0l@f05zHTsU*$uhGG;__8lDgsDVj|5 z-c&if^i40wV-}%P5@wvr#Su#+`5<9Ul)20Ry?@QP+Sp_E%LAW#)NCinEi4q>kR>5W zrRb(WjJm=A?}Qq9cek~(Q)zO_;z+2S(}~HP#K_h{SV~SunPP0!JcevGV+m5QFii+Y zf=H>l6ey@bz9UWQVHqVXL7XwE_8Lc5R8CPwBh>HpdH`-hBQ)ssdcj{F&ilbJi%NL? zMGyJT4&r27WSUFemRMXu=f`xCaney;aadLdp_NwJf+^fVh-b;6c*Bwt#-v%M_Uk)A z_zt3p_t$~K~n7qtQeY*B_gCO6M9IeOp!W!_Nna==8 zW5pk#h@mT-6nf%S%M#sNsZV;Q){qvfcTh|dRRl-BW&-kOs)2-rL@y0dB)mi;GFIeKiTn$NTSBfJ^wJn1G>+NT5qvySl?~iV$A6xx zqo2ddzoaRm$sETtLN8)=1syO<7W{SttoVvcn!eP9PjXUG1a7%jG$DyvNyOqAc%lu* zSEb$xshAf{4LHk`Tr*`%ovSF#c*=z4o$?+QxntA#ix^K-x6C@owLa?9PGceo@KWw` zd4wDomEY0zJS@cuos~PO@+#esN5X0qyRPAL#m$PYkBi<5OFI(Pbt78ZiRe~(5S8(d z+=(&h{XkJlxB!VjA|V-9JB8+ZS_!j^yFTT6Ra3$r35Vi1LF5Bg{e7ee{*+y*5phBj zHD@InW#cj7r@Eb=K&rGv5vB9c{f&Umdq0ulvxyL|6}>8aSK{Xh!O_p0O7b=diJzI1 z?qZcPMRv&y!4U2BexSJ|v=A|ybl&{nQ;FhisVxVk-uzHl9afc~b^{D$mcZozi4=(u zW~agSEzuMft0O=iu`v`ya*8F2Xq5cF|MP#9ydl+TnJf?k3ZX!#Nip-IeijhMgTn(B zl_`a;)NU)Tqx{s3=_M(g7vA}yyKPpZn6fO66xJA}oJkU@qajy@j5!R=B#SWzW>5s^ zq}WVO%~d0od|c5u2BwfEn%B%>Vu7wm9IJ6wQUYi3oBYbjTYiUeb*r$k8-TpGfTUW5 zu8jb_&ZK6L$p=+|&WUD6k4h~nFiJ4C(2vT{TSind8Lsm$IGY{DvA_I^N3P;MP7VlyZzB?f92FIgtn)5j&vOx7Jgcdn%WR*Hr z%Ytghijh@%s`{Yym&m)x%MaIKKlod)U#*2q&&Td~&&$ZT*iMOOEQ}mnJ2s3R$;|Kn0&eCr*e~O#aOHWz3Y&{&F_Uq{@0h zNgN$baWWyM$65w)lCoqVvdNP*K#+b-m18DtdB;liO)TgPPOwN8nW*5VkYEHdm6Lzj4biM58pZ^~{cO9XHn zFJUZ!OR2Dw0*?2b6zeqcm?$M*4$=EIAkqHCN5f)os#-j9bn6g-+#(($&MtvFg1pX@ z;3y_S1n@Hu^Dro|2gAYNdVd=fAn2(tlVz=+|5d=jlV=##@m#W$hC>AZ=+S?!c*8SH zW5Ug@SBoY8IIL4W=Tsa@b|e&q&+bYKS#@`Qx1|nT540|8ih4I-er1U#%W6qHDHP8y zzn0bVuE_k#<=d=fAZl;EP%i5@pnBxgXV{mmhJ($Ow~|^IW1*FefCAD(tl*f^C8^1- z?y|tNIbeGwsHFN_4O<6l2@of3^?#sSVPOj9YTEq%#L~6bL}IIe5RhG)Q&Y3PR$UFp z02QlLKZ81V+OW(FzqX z4$zhAVC+~$imjU;9|FF2RDG9+P>SVrh`MvkyD^(|>kCB{y_3z+8kzGM{%|hnzr9vn zRyfU)%SxuWr0IFglF2!!*!?U{aCEN3uXA-^Rhz8a7J06>YQ2#vPHH}wn(Rc|jVILY z=n-3MuuN-OX)#2Ki;js5{5xk|aE3oTPb8;G037tT>3gwbnh%mh$P*G0I@hG5LL`i& zr8(kmL3V01_$XZcYeX=IOW$^fwjZIkk{Q&$9r(X0{8W{NPfYz^$cSaqa6lD}Tk*1_ zdijxGf9&_neMy~u4yp}mY7O?GmSGatv{?897%b#BEk`Hj){BNE!ven@d+$=bWIQY( zva^Fu7m36l(9TY42cf^)OG>pRz8kh+Z2x{q7T*og-@*LpyVj1X^<3{Fs0P=tj7d|R zT#5kC@V{AtuLPJ)au$;g=E)HK{e;Ej@Z^nwazaEFOVmL)ib!NHbIKP)t`W^5LnBsq z-LhQ)>sEXsfM?5fA!FTbk{x1*f%RWI+^>Q3jU}nIN97L=ys|F$P5yA|FWD zg5pkm+i|y9-W`B3`+|L=4*=0J1o3ztT0@u}b2H05(~|s7&fN=w23t#OppG*{&7sd3U7jUy#Qn-Lp5VCMYH4xI80pKnKst@${e(=Ykcv>W z+h!ZSE8G{4h#DSw#q?dV8cae#VPKeY#@*G<&sy8&jMLR9fF4sDtWjZFFunmKLUW3t z6+7|oUOqxpYDK6ZQrCukrW$Um(QPAYtl*5+5mXXCJ4K%-X9nnHq9<8|B*C1rN2>CI zW#|f2xS)&m?xso|KrC^e3`p_FG@-F0201fI47FkLv;$Mh=pXY#tY|R>42npH^#Tph zY@-HJO|>IXJe)8lpHU9l^@SS^Yr0_c8j&r4rdSw-O$7HJRTx%*%rA-Qty)sYoQ&y* zA!>)ifBg&c1$jl2>_e?EtF0KdLkO(ib50bmXPNl*Z8LTCj;-FZ%rlzzf?jY?xMy4q z+HCs5S#RJy4*J2jMzahW(DM>tCWfeOX0YAZ)H2ZdC8;JY*T=U5fV|7f4M*3y5#*!V z5Bdk4y`bOgjI%gywLD`ub7JNU3%?|ds*KX$fr-F5*q;qinANH%T!f70R|g1PJ{FC&97B0dk_k=75VZ~EY_EWdFPor}#+*sx z_^3%Z%pyBFSpE5e#zeE)hW6IrpZYto-8j%^YARu(0kV}jJqsA~se>-bVhC#<&gP(K zpJwisI%$j(;uIo4a?3HUNmPmA0e8AaTcjxbCN`!CE(GC zuz(RwP`ha>wS$%+?5dW8hB0(mRGP~V%b?}$`8rDh%}K{}P7)%-F=r#ozK7|lBKvN| zXpv^HH`vp{7f1s*enw)vI3*!VA~8gdbzVw11@lV%wZCsjX5oU@Hzm-&3)WZg#ahn8 zf_tLv@nH`OYtFFPfwoh|3ze z?={&v0+IhziTrj`nw;18L-G4-GCTi18=t>2l+Jw3Vo4Q0b^apG#MFI1y`<^+E0#>o zUxC&@e_uAVtt~fo-M(ws(CcsKDg%r%-w@(sblf6_P|~>WQxEy)P^|*Cyr-t(VMqt==Av+ zI{WeEDSG$j)$`L+^gnOkp?|)4`!o9a$HO!Db$Id|J$w7|%@2y~ooWKBFAIg@uz|evG8H?z6q0a+19)TKXe|$hN8WA*8i``tK>JuZ*PYiu|3cbjsuK*n;3p?r{ z6Dj$VM#jX$WPlhdr=+#xorEI>h9J6SW3(2LWIc#VPO>-3G$v}2(1r8ovfE5tKm)BE z)dZa+ig69@{XW0QRQCVOC-cqQv*)LQ{2;I0#)|k4@ORPwbN|VH@819OE>iRSpM#+^ z4Rb*nnD8xJgICP|!T$c^;`|Q=y(fG3^M4oViqtDAuL0E z>_|X{wE*pcFs`iPir<(cw_gwX|36wKDan;oX&@nJ9fmVzMxe7Wj z0;jMo;GhKs$x)Xsd>TS!$^Hk=Vi=di49r0enk3O??Pv+LrZp$JZq{bu2OTT!&|;vK z-ZoT7D$>A;4PICEdviw2B~Z1gX**vS^i+H>(gUf$>oLgnrAIB-^7{yL4;xNGnh*gIN>B z`lH}M$dV9C^uV_0>8p10uQ?um{;mdA)E-{rJn}V_x=2ZPc_U|C?pE=8Sr>XE@Qor% zm$O=}^;kON zFHDCn(8I35<}1lkG<=H2lnaRhi&^&}l4*>nHg|W-ku&cw1`)ZrJJ^rUNTQ7weE4Y$ z@Hv~o06nlg-~%;EA5eh$yMV6e9aK#)9?Xf;;vg?Hlh>#zIeZFGE2|9{?zeNoW4vf;(U@AGj~{Ip z@(EPqu!MhRo_`6LM+)b4{(~QW`p$vr7EtUThyyfYsmjr!rM9~*b4c7 zf3R1I|263C_wM6=-bq@zf9%X}FZkOCou5hKuXEg z^YtAiwM9X3u&MfE9R<5}3!_RbhY$EThKh!0OX9JmM{Wc1gERJ{<%v)}(t%8KLwv2UsDa+)2QR0=o zO8&gUl{1%a60LkD^9z-!42pkNVXCya*Oa1Mt!3hq&u3Q9`rI7ye|B0T|4m7p5-!xN zT(6Dg@?ZZ+e{ZjJ|9^0Ba3BBqPLigKbT$Oro-vJyT%_dbObtsoB|}S6x({2=KcqGc zh4svJ@r#3&BR!1-L{-YEhvS9xiz7-F%lRTNMlt%NSjQwp2an-TIy=qAWBLKLJMB6O z)_vG=(PV8K<1CIB=(h~V@EQfeX$oBkT0avF9m-49hU$($Bckoo1e+261pytVSs&ku zgoDkyb?%}9JpeN;f}XuORb}DGOG&sJv|f&pd1*ldF}Cc&kN-?_n=mkUgXokln)5ni zY$H5-RN9k3O5vYfnZ^QZjeRU~NMAuehELa@UJp+m+ly|4%V4ZQ?z006p+86&2wxc?pUm~h9r+vZdYjT_eB$w31j?@ zMj4GIO=`3(k6Mg_%a#f16FoxMMUnR7pPLZ@++~+O`(+q3ah6< zbJVy73e?Ek=D@ybHJaMuHrRPS#Guw%r`J%t-MF~@y{G>++B@_K^bD#4?Z38B`@Fpk znbiTOwGM6#WUaDJD-zR^<+(OsUaIZWy8v`-QxeYtG1U)}tf*!N3F=kbg=L)7sRog^ zj`Zjqy7y=5VYx?76sSrS@AB0XG^+k~8fvU|PiRxjp*S*wC74+^jv z4MXFfb;FSRa^^$mZ`N)**D`5e&jtkR+(Uh;plT{;-luN2@+lm)QTu3EbJ+4 z{bV&NjnkX^Yl0M|o%>V0uiOMLpHgRaS{BRkt!GTQ7=w z3>w$Pp;e~GR7i;btK&7N;2kNPOWGV$&NAT{GNmjMP6e+W$<|@i4Pd=|-X9;HoIXF% z0jYp3E~LwtO(5%qj=Sk4PA237Z_((xe?@=YMGyY*_puq#?}ESX z4i$Ww5dG#86!}G!nGqrI1d0G=XLLr+|49}(W)6!yztFX>XJ1F?>$BFXfyo~{-FR#i z3QyaG5efdf+eR>8Pu<7`f89khF@cgZF@Z8)ZQH9CXJ7v~{QC9q>(f;ob1uTwUYQ`9 z*F+%r`qdKZX!s+w|7^4X9W-SD3b{O%e|4do&HAF`uv{RMwbt-u7w5ovEpJp9Mr7>@ zXPnN~FRfjrp(h1Fqn4y-cO3LRl?V(zQ0~@(*3dCFdc@QmH#%sOp{&<5b#b9rN){w# z0)G8w>Ka&kFwgL0<52{UpjE@SVo;22Ohswc)JMPk+MV09W9{msZ0KS&+|IMAN-JTj7lY^zY~0-(Rz#sEiA=^-K;I-FTX#kz&(jI2Kea*?jH ztY{L^IgK*MSDlb?-hXWd;^Ck&{AZ1u-1n(DHQRrfB?YRt>pcg)%Kv|_SMvYwKiNNcd~g487pcTN z@DUFEON&mYQ!x66e4NQC`M1vmv6xiM{#UxmJM#q~q#PnHwIEOu zJm_j(;4THyf^S;zo8eTz&pgVj4)Pktn9fWVi}W8t$51za!{wTJ;JENj{g@LzvJHVA z1^$dkOw6AXBH`bd3jIflWjKYu^n)nyC%me)UVlgurHoos@@KsCPZs%qbyLnhEQ)AW z5L(uD$2^E;CbI?`$Zi~nbsNJeOiu~8d*()W$+9JGYVx;kZhtBah8;vcNRkK$HoXdA z9r9~NlFxzg$doOi_$wRTe%m2qJfewD2dbFB<#h>{ZytVAg|@{KTzB0SCbNSQBCi;~ zR6KA~Yc!c~A}WaA!XTD#)6Ym(5mHpkcwj&gdXuPSVkwH2PUonWyuKP{OTW*d`<1`f zar;AhO?)L>;|Mi0 z*u??`&Q$kQGl>Sm?XTh`=R-sV&)`mEltq)fU_KhffyP~>#K{p&B1d|>?}q&=m#|qk z+7(aV^|?i`&zjbf|IKu4s|HvV|MAI_gOdM$zdzW&m;dh~-KzZmy|Mlm0^HEnhCAU2zZzu{-ZAcaK@d%z4G|^&BTn!yGLWv2l z+$#$zUDs);3CeO8B;*eFp^awYCIb~-g1AX6x4{$D#pFm?WS)ZbV55d>l!x$G1M{LKGddY$|bbQcfAf(y=cvd+~9~S%tOMSaDS+D^CNv1}hH% zZ`56{P488$!mHVC(fD43g()--u(r3ixGS334J+9aPrNW2bxwF~4Md;LKXTFSUAL9$ae zl`<`4cr$#=cro^_DjXTifi zp`Z4h_bh>}hCEFCtgX7<(3szj`O*ZwX$P07R3+$Fj@26DSyO#E3QdH+8mt$U16Zw1 zv(`8c#_$TVx9RMcttn%r4L@jD9=NXhEZgVQl?^883%YVhU#IB7{ zqPB~^GTNQ{z5Rzy&HLYe@h^_IBLb`T|G{2)|Mwq1x!?bHlGJgYvjO&^z3kv`G{4?b z0L5>qmdSphR!ZIF(OMCsk8&XOdM6)?AaQ(6QOERE1-DWpXiu*E>PA9Pe^sk|%K7U8 z+F;@D$~PL%-vM1+d;c3tj%_Hw%Kg7zj{n|&^5owB`%cm}`(H1GB^2PTUMtt70UFG5 zDxh)s1JVJ5_~)hstM|WW8M&nluwwrY`Uh3}k0FIEiYC z+TcN+2BButH{0WO=Y1TfQ%3-v=WW+-f4AY6zVvV-yFXV0fr3|m^d59*(Dm%0WsgFo z{@ad<02g#GpcJPpF)tKAGwD2Zul~6U3ea;wwEfpCvQL9~AAEgetpb{p-!gcVyr3}_ z`Qwo&5dPzmMP+DYisZlR)vE?X&Ao|ht8{VFs7TF!fHS4~la7%cJ@9<2Ed+?DQTK{y zBA>S=X3#3$LM>n`pwR`b%w8zi-&c8Ux=n>_AC6`Uue_KR4C8 zPd2SS|MP$m+iCz;od5m)lZyWD;PJuz`F|J5JJy>{^#}gj#5U8dif8)WnGM=BkBSlrnf-FJJap~a3UwM6{rlm$uUZLGGV}9e$VXwGkDa3>> z+Q}@h=-bH@2)&tt((qdD%0DAYMd|_o#DaKLn}VBu?sb2kbXraSa}T&%vj6YzJ+8=q zy?guryGfNxZcD(_v~Mr{HK={omjHis&95l{dQod=OmtPl`+6U)!C7m|rljfoobTq}uq(PwF1VWQE@}D92TvIszvz}6`>HoE#e_ciY z_xjcMUkCU4zq?7R_5U~a=Ii!s?e)yR8;`iMh*1~IYt^&vxun3Zj=(|sXiCCMD;1do zs6KP^R>UPuU+Sj{PKs|f*5zEM7w#RDQU~n!rLgIEna~*JB4a@XT3^^Apx@@LvzIMb zs3-GAEb&3r;=aZtfN%So9~=t+zZzecTz+hoU>h0rMa-^rN$#^|ZW-tfGZKs^KEJX3+ZM0N0Vy(~HsNF)?&4T4-=^oVt=5z|&>QmP1 z-*2qG-YCJsvD);;-PDql7o5!wy_PnVI?dgCfuRE+;zWiXftfgK5xvjZ`5B6 z{TT}{3D*&wkJv25l8$Ih<>Ce7M<*|RL{=2t9D^`Frrf%-A2t~CKNS!CM@}pGf6>L4 zqFW4Tv!N`oQvcI?QsVyy2ZR1S|9=^zBZ*BIKz`6YOBG8pQ>^N(#NIm zEw2b*TpjWnz5Pbe*M#X?F|G63i<)ImiMSlC;^J(h2k<;f-Sg5l%eZ`r^SQU-XG?3+ z|7$6MR@r|(IVjWr{@_0T$K9l*^xugB1;W2A0pF5ruS=XZqIkI)V1pK1VE$#`_wI!F znGegTo-^uKf6xDYrnCwFM^^KH=6$VelMAvXzelzp9NY0sUphZY zmhzK2gA0XjTdOeJ+YH$)F@oey7(ud>GX6Qzn)LrR`M>_-gU40=@1FkONm`5lBiHBu z$VU9%He`Hz{_i$8z?!fQ25vF*PPZoPqUIR-L*Pne7_Eco+jnOxHrkl+E6k&{F#VAUS*%@02{~i3W1np=7qC{pftZJR z{}?a99qbMEdR_-5U!1?9Gir;yz%e`*>5~>kCzsM)Q@Bca?5uj!2caQ zuG;_X-{1e=P5RvY-}Vxv0$x-OE_urYmhUO4i?z^h;3zx4vWzDM0K?W^ zCI+^5ftrgc9_$~8Y?iZ3+l?$j>yEB2TYmXuo1rX5(^~cvhFfc1sI1y2Fq*ZHFI92v z+~_}Cal=a3e$VG!D_pbo%nAf~MU(79HRwC4c_*M49Zc7Jo0gWCPI8fwA>xU9T_VG7scAh=dW|*%X_iiMXQ})`!>pQi5#PKu zlV8fKDCe6xq|vXB>K-82hN{??H7c9B zvRFc^dMGZ#Y`QzrDJ7vQEhv?M#r7R$1x%PX)PxWgTxr57{r>Kv^nULlq; zCP6CFYd%&A?`U4PFYp+&eqFTiK62r?<~#r+bkOE+zM4yM9O30>ORu3dO0;suy_alX z_}_ATnqP61Hi%^z!Rwpvz;a=eZOK;W&RwM?VR5=jI zxxe4Lm;dh~ZDRkUs1i#_!o!tjK#y<4>$582uYVtOZ~rqHqPAmBmv{ll>G?m&VhCZ< z)R^9#SM+kf6kTFd^Y zmhf*&(QlcKfAMBOUnJ4nz?x_Ynfu&}`95u&)}jB|h;(okQMsiUu!8;%27_|^_r2c1 zz5VB%q>cE0w-By<3}hp6r~qxp-a9=0P+Wd~L*%-znD1jw#`Hts@%;k#-}W}3+NMt1 zyp{yusg^gH4MpwG@WdAqhNz54x4u&^j2z*0$+{Z2GarPBK)KF!$U#jMwetN&z64DmzBI;(E75L(_a!)BE;Gh!!W50L*{>z=D_2j>sKltzFxZm)U-<(*k3L(8cq{2b-#RV(c;<(sE z#JoQs?kcT8|M?}kRsWyqR>18lnZ1 zDQ1)ILp3FT3a^VBKM2>P|F>%Y|D<2m|MmCp-+#HAv?cuq2_UBqiuVU2@-b?E4QApd zqwBr9*mnC@Q=xX*s!xADVN5=w98@NYYx)TAN&t}?^bz2f_W4o^cYkj-Sgz+KmY`+0fm#6emGV;dQj7f(pSG?6KSClK zX^71bzHmQ>MjQ0JnICsJ>)nt=nwv!m);&=3S-= zqSrOk=Qa}323`gA#1W1o$s~@?edmhdQ*^D{jH+`*O(TCG4~`r5B-r+}{em0_%3Zi| zzk#~-`lY)IR0id?yadV(UEevN4Doh-08L~vTGZZVWnj@t$+^(LY}tvTogrToStUUxPQx-bG=u(2|4 zsd*aiTMmHahm86IN0j=*AbKDAY89qm+9k|?Qs}F7`M>L20IjMya;HoS;$F1-Y!<4Oab^8kOq$Ov0CStJKh$+qhp^ zvSt1NH%(0gb&GdS4Ncz2?NbBnTfc|8ArAXKIMwG5PPLBw&)Bw}-#V@G|9(8E#Q*3G z?)|^+ByHmVtrmjk0OrK4S9u7i+cN@PmpUmNi+*C2W4fjZ%@#G;&=oF0)(YrUUlr9w zc4{tK;noYxuIbwYCwp@8TSht2S1Y-vdK(4CxM*C;@q(V@W0YGbm5T?j37?SjSIoJE zyANhEHUrUa)iCf|U;|DNWsG!4t4*;opl%GaGfrn!)YR84a5KPe1UaMHFQDe$1K$KO z2dDzu;* zNp(e&h+T>2T1L(fsDwr2P;F*+rs_7XXrhe*%)yv)Hm0%8P=Gw$5ma}o)?Bv`*^2~U z-QX*abtc~8pOF8)p@{X?|mvNzAMx{~EJmoVM$T$yKmTRCul504n)^#?jT?(DtRdS2v zP|phKq`sb?;mNtRKrCJmm`2K>fb;|gbIgO7jsinhp(`<)1i4bI6s1QeqfoAEs2n4x z$(piqCsD@^xW7mXvQx=vGO1o^R4x(LNBK4W(2TIn zTo+vj?52?|y2lo37qV6&S_E|CXlAjbF-^$1wu>twTFhLHY6+N!>?ibF#w58Jq)#tt zdj5(flk--7M^e+o;cZinhO; zW3+s)r_tm(B8@SpnNU`Cdq?;=lBslTk$VZ z-DGiG2>j?>2Q97W%DI}?atW}a4<`iI6x6>ut0Cqe$VOGOeWl=QEZlCg~dIz$*Ixr1!X_|Lg4y_V4NcT_i;u zbWHjO!4XdJh{jY>B7(!?m*!v)!H-y=wpj;?7YZ3COavjDb?5!|t|M(;5wm(;o5j=M zIo1TTcn%pLf7Iis!VNbMlcx~_U_N(SV+U9EB3Q$8dD9-4FvTQ^QbrSNuaXvzDr2-Y zBa+ilv}#3w=1%KsCj?rj$;9=#k}>p*{+dHH*UAQK;=-#~@U`3Dt8L${rqk-I6ilu* zT9Y?rF0zvTV=b&*M+{g&|9kuUW&4lb;PHL@|2s(~9RV1-nn~Qpn zz*BGN)(ZNLS}jGHD1QlFUd^d_|4Sm|IVT~Zb8;Q-Z?*sb;NYOV|L@=bxTB=`KWF(* zggmiRZplE|L+iR~0E;C<{pO2#dELV4T$Kg z$7^%By-e3jUUwvo*a)p+m&v4w>HL`kMb&azp@Y9Euy{+@{Rg^?;4GD$p^q} zh}x28CdOKR(Nj5K;d13Ti{n$UhxRV-$~ndRgk^3(l`FYro`9;aM^nsYsi&yu5m-wb zAis10g!!a!y`zxfIGK=o5UP0D5~Jg35*zL}N<*Yg_LmSbSEdM{A$%40kDexKR)P{>HlEw z-v0Ye(v1>#N6>-%wr_%TH~TPymvTL6tMy0r39|l`Q?-ImG5~&9b)&tx;h9r%bt9v* zK}FT(O&y50J{xen=&>voG9Q=B+{6VkaL0}Qp--33z2CmH)J*^9IHu}o?tq#gjyoZb zwmS+|>VF?s-hUbN@A>~bNjpXWm`L;>CJA~FGj^G!sJ)EZwNcxnbZyjD|LyLg9_Wg9 zbcFmd%aRBUpQ4C{(#sG;+Du0f$p=XiZEH}Z9o=~!$LSRJyU*t&0b6Fm+r}F9+Ax1) zViS;!aLi!5h}qSR0D24L?RucDfeeI+=sK^NL+yxpZBUU84}2|1_CZgUNpijMd1Xz1 zuYt`QYqfnnRIWAM8k18H)ZYAX{gqe??d(F5|ED*|0BU}C}r zM5ujY|2jH(CJ^QX&8QG++|V)H2_VA)AUP!{WSkR`GKjsSs-SR+xkMu}X51B3d2&jH z&J5s;SlK=A$LBs5|14>J{%?CVz$*Kny}gS4&))vM{pX#eosB}I*wT!n2U9Fgv+0Sp zi80`@iX#*;BA~G;o)h3_Dqzsz@k^(!ax73pg+dw~pB@WD6OXyEoKMPGNQmN!g5~7o zOCl}h{U1z8Jfo9@adKmAtlIzk2POZH{@&h`{{8;Hi?oA|v6O@-0!fDS#G|VzNzf>x zF|hb44lltWy0wGO)T$R*3dSBtOi3IgwZF9?7ELCPz+PU`IRUQ#?>kPS)(%R@1c(WG zkU~rgV$SFP-VM;(BwiqvKuv`bN(o0XO-RrRo}HebO2$cR2OY85j3wx&qf-=7E?U8a z$}aq0qu&Zf|K?rzzx^v&t$;=ZcXe^jer*MF5weJMTdk0GTPM#CpS^w_ z%%Whz8kP_uXu+hW5#D#`!fAQ$VE(^j$HXl^gpzI)ma27{p2>8)r=Rr`9-GZj0oUZ=OZ(f9xT9&<^@IFx9bjaIZ| zi+(-mO|y~RAsshRE8ENATTs(%q~KeM+Es@w^vLbM@@(w3T1Hce>?bs49OdDM& zA(kMcW(99Pr@akYt%nbPWHXZD2^l_oi2iPo^4nF^QzQ3XtF^O(&R+emXD9!w)w;O2 z7-2DODMXzXsMDE{MBzd@37!$u>0Dtd5ewD!6 zv;ao}1~XDRrlDIVcY+Y=bWD5btDl~qoW6YfM&r1%gI*?*vnbP+Ev++;2V_hN$#E(W zM(^#Ey)_{7m0-p>WUJ;KMa~FY%`Han^C{Qh%oI9%-d)G!W z?%FdQ&2WMzga^>MV@^Q27E}_^YIXcY)(`rB`>PoOr{Fs}c_vz|cY>e`Z47jj3CU(B zhIf7nO2-R5n+g#$f2?L1&l!!7sXN#1ePw1HmqoV#2A*b;A1^U$b)KN+Q-~Lnh3x2ge zAx?m}9kDEt;OnFQf6>1{pO6BhEpz>lGM|vJL4+>awQI0EX1*w``$0b zA?avgw-du-Djj0X;+}#*MRED~R`Ip1DB||k&RcbI521h(PSY5NZW-yBge)~=7dTCa z7smEPkBT+BTn$??B(jl^RAw??I;y^Q>`-kwOOL=I4UQZuq3a0om4%7ZR73Ke@jf92 z0rVA&kH25&Elv|sD5M}%sC&vHgIOKTLZ1{Vj}=%$y*?Rt7)_rtb=Hm+s7&EC#5}f# zBN5;BzU?U>Kc1Z(!<>=?OyyCM%|^tpXIu}9U2A*&X%9dC{;2KZkF$_u zlvycceU9&HCbV3ciyNh-zElyb+359SchBt3* zC4{BqbdkSn0;&7~v0L+e9IW@beqt16;Bgr)Behi7btY0@6r z-$Bem90zSz;6==?M0@!D7xzWmK-h0g$vJrg?P0t9sBQKtm|ehGqe=J)(Ff_zj9GB8S9paXY2(njnyc?em$C!@bZ~f#^*rt ze9L8MK+aRqf-yg90D$c57mF%|^i772_iILKnwyY8RWpmOCwX8;oi8qF`Z9sLH8-6O zzA*MEy6BaQ5aLG;ru;Q-Ltz_^LDp1`P1#oMoe!h$&+raitkgnXrssj!bFG)phzs zj6oA%FWK^04%sY?i6rr&9%>Egec>Xo7I7D7x#r6qw|SLr$Rpt{99^U5ipdt;8jPaN zdl@b7W7OEg=vKNH)pgDirW#zd4PEEW5B|n0EgBz`cZk#yUB$_4>Hfg2`=|($n(^ywTjp)MPQ2yH7D6Iy(9%{?ooF=AZEFXDa+zW zp^hQw2niLn&NU{W80BP=#h8QaBm#6&Y$m6dph-3K0BJ&WRQdkIK`+iJF$sLO-fN_dAnw zW(~|fWTK-+N*3n4L=6N#H|1+$Y&Gx~g!`noYK0y)7@GQ>@Ftwn5L?ee?=bB7+NOg*Bp zCF@RNgcVKDIFlJCyXt3%1+=4NZpGV#8a0|AoFHnkMq`DxK0E;A6%}d=XR$d*M)uMq za<^1e9pA>0xsJnr1{R9?rK}@1OR+R-;05DHCoh{vcU46@th$_P73mvEU@2T_SZb>L zm6@e_!U{5B<+wQVGZpiqm7z8DjRe^Q!DiRP@Fc!va!F&IL~A@evJAN$sb#aJb(h}V zBs5l)y<9d%UTt&zvK)5#GR6Rfdzj6kHQc@!pkD44uvcD0R0?d=NIGApSJpWworkbw zmjS_HNQ8I|iWLvV_6fn!&zwr~HVH`^Fcy+=g;N+~p><^p&%sGBBR70}nAS`}b7N3<%SZ-HicZCrDauQiohuK2ZJ zk7-QwpVfhJS0KnQRRl{uV8!1Iy?9;%zI0R_9r{bhe}F2j* z_`|t?=eoR)Av__Le-@WCJ&##3Igj;=PRP7abgra@^C`gv(AAwh%!8*5n}$h~@@Vx) zl?tvNEGXa6gVH!22C7yQ43XmYVWOR$?!Dz1g~zXZl92P=CMox@o-g`u6Is+WcUR)?Mwo z_6PfZ`(T3e8YgtDDpWS`bCs<`HAy_C05Oa=|NK!I!tJ+k8VtG!nB_gfXnKQBh z?~;cP6DA)%bk>O%rr<>`o#u^O_zxJjs?=n%TW*eNY1XPs^6QsJXq3qom2gQivVt~T z(3q=sZA@3X^0_cpUXp?1aqwl?q~E8zOJ)0ioTeRhw9d%Q`2Z}p|L^yEk1PH^2M725 ze|M60(1~6F_R6v?SOLhRr$8hHa>O>*9)hy`f{b&4BL7o%r66a*=t>Ee87GerCu4nC%rcJNs{zi3-@ZZYhTcB;IUfWcx+Jkv zpngB;?rH<-cj<)V$XI532H^94FxdZVt92?d*9NvpCHoP2@7t##U;!x+>)AJ1!=`S^ zqK>n2GFDH!+F^4gTY>S z%!!z~^BX3wG7@$=cORKGr!H0^zh*uCdu&O!`64`Wx;FJ#0`H0w=EWi zul~MLjFAv5q+lJOH%qcW$EU~Ml}dG5XoALguEuhlukne!=Ol47T-Mnt)??UKcIXyr zq1&xgw?yrgDWIb!8$5Ou!-mlXxQ!T47w7?*lSB=tYG8&FeajTa1Scp<^G@!nMMR~( zFN=xw90r#LGmLtbj5xa_iN2+P0i#96O=RIz5AHbQaA5&3G*N>)d}tzJ5~O|fz#yEM zwRrKU)P+Zg$S~Lq)JVCp;(CS!nh=SE%)(1|!3UTq|&jJ2lHop8(pwiAuHNr#K$xTi@RNI-?ce zmBFHsQ-X($Dxua%nSvcg5DLe4fZLpeVGE?Y>)qvMf<(@{ym2PR_B@D) z#568UjXUA;Id_v&x^7pC2{y25AR$+%zL(mR3Jeem1x_VSBFrP9&j@$pYRrFgNhm-2 z;M{9C=Pb!ImwyoA(O&fl_ZyDxByj}Q1bsx_{kr+2u`>5e>*16jl1R$k0xF?o8^}?s zZxS4!I_SNAghRm|EakunC?96$|{C3BKcFrQ>&qEq}!($5>7;V5JIU-lc~t3ee9}8tX1xba@8SPS><^fg%?xisnvT zPN^mo&aY^aeJG(DF<{Otg8?H!1zdmxNDZsG06_0XSt7H7d&`BpAhB2k2%V|DB?+IY z?FHv}rE@$>&_#$P>Jk}tO>WnXn3^s02~9XjQRg}O-~ZbA$Emwa4l{{5QTu5db;g4W z1k(%@1e!`%q(ofBHeRHJ3-C^p7ivg2kr_`&)PPgY#??^)D=ViY0r9z7<&kIUqf1oqXtiFBfjiZDQ@sX6$mxhg z$l4TH^d6OUDmhm_A_z2>K zsC_zOOzOFt;c!Y5q6Y*(lxG0eX0^+oTQzl`?jV)*zp%bVCl8_w(GkY znCKM-O!2+C;kUhSdo3U85Z<3QH|COOq}4LZvzmjDZ_H>PeAE~5IF8L@0QvKD$i5-y zKU~%^j|>jc$NYh_iD&(PLdIf<-s=nGU-CwciDR)@_eyrTT^I$gS^LKJaEp?)&)_rV=tg_xin0_vt>}r~9;B S`u_s}0RR8wh0Ck}`~d)MV=?yt literal 0 HcmV?d00001 diff --git a/assets/rancher-monitoring-crd/rancher-monitoring-crd-105.1.3+up61.3.2.tgz b/assets/rancher-monitoring-crd/rancher-monitoring-crd-105.1.3+up61.3.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..93063c6088d98d4b8333d773bd40b9bda90c9533 GIT binary patch literal 331943 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 fH*YNl#b^9YkMGQV7DJ|G>Z&rM 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νP?Q}o;C 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 z zbD$K!UEIo2*rVfsGPYd=Gb@+8>pQkbE=YUfQ!_W4cpEpjS{Mm9cne(0+hy}TB&lS$ z?$FN&SG##R?C@jAEXMIsa%C%3D@`?n(6oY0E&R7#fn271YNL{_1JBq9v#f2Zw7D2= zVi5y~U$m{DO2!pk7z3GRQ8vHTn5kyxcrzK?#wR|QL%fyg9$A8E-6N&d(4?y9@s0Vf zuiN>CXG|@X#xPi(BmKc(-<3kWNR0s0aQADu0eh`JbaIM|IS=#oqrBbgBo0EQ{rQVr z*XUVCNsaxg-xzkI_0N%Dw5=~h)W$Ydib2?Us3g6ay z)|b{D=QIjHP`dg3CYHHq20TnCI}dk>_@ zB#24~sFZQZF)O#KS!*a2E5@^ur|c{^6x+*9#A5DzHplBN+H);|zGF)jxNN-u6WW4g zF{6gt!FvhSY$gl-bKk)_QHfmGtp*|Hv?>hsmM(4mQYYUi4EhE{P+zBX%Rq0d<2ZTAVMJ)A=dzsjWrafa zYZcOzQ=4@~sAIBVC<6Y9IW?FlR*7?TVd!?jjlvuekzJFYCq8{*QSh7=JX?Yg2L+s_ zvamCgg7B2(3#maTgEJcj3H5Xt)QReObC85UHaL77%C}EBE7WgbMRDh= zJvRQ-00hG5Eac%<_dRAGKYr%%p0bVynDyhbjR$5L56Ldl_q7I9Nmq zW<>gBbZE<_VJ!o2L^kEuPk`_ASlCXx#dUg2OsB`ea~go<^q4qKkA~s2U;L)MV>dkx zZqqI?oA!m*^mtfJkBQUt7#K~DiO=*n*i6wf{3BvA4aQ@70xYIyio&M*;IQPbV7!ck0(Lnc@iX^r$gb{ zwM@Qwh|)0BonfcxanN=i7ilN*@@w81T*(Wm2pmiI_4&%^pB1FHfk#KgF_6V0Y zGV$^F6ecamC^GqJ3i7si@nmbr+3AtAbzf=yP5e(oU zImip-9({YhiM~2i{rnLlhyos7u!Qk@rWzPM5G5;Lf=~&ZwmvEAQHsWnL${KyIJ*bl zQ8qD*YZoDcp|<#m9flEwGNx^CUOb=xA#*Cy%*bGUCww!EhNIR^N7M~vsZmeoO`&26 zP>EbL<&57mVQ%Z>gZPHosM(%YrxL=ql%^u3MM}Q$=i2!fmO|4{6Klyu?YxiX6wIZo zeh?q@7vy^}UKDJ~KOvxrf?t2oW2Xm@zS9XD)`iMg^%ale1betBm6l;pQC_M(<5a0w zo9oe!7M9S9b03b_Cu+W!Br-qCm*WJw_1?h`M<2xbf);%}V{*=|y!YmgF+y|rc%oAH zA;<#ap?aFEQCd5GXvsP5So%SDQ{el zGvh@@1s=Qg@xGxvW9b%SHCpo&8Zlk2Pr%UHz7-~#6*(6)!-N1k)ORvvI7qAC>}Ew_ zz+7-OXK8I+qa6LH-$W1|o0>~Elh0&gE5)lq?b=;E=;!UqFz|z8( zM%QPb78ErC3gV(+Nx9+Bo@$Rla_%FHAp$~`j@3pk7Wc^ndFP~s$NufuvY6w)_jLW= zxze2gbxCIK45B53nRqbW-MZbJ^5^w z7e^}^M76?EvEFEYwmQbW5s5*na^a{-$%F$+D{M%$$2a}7&xQ+Ri#ZJvf4!v*jAv$E zol)<7^c9VAlcT+QzGej#Wk$PpYVEe~K>>~mbsZMwIw-{T*@m}n724XP+A5+8n%t?H zMZZ^Jbgfte{0|q_1ZvJZhtN;F%Lm2wpxEwHv8}Rk7P2ts5z^zMkX18U%v@GaU|;o{ zYZLUWPQx7C?$c?UsPRE?Re|QAeC|)#Po>m!WP==welms*QQWNc3vAZVa4zsU#9m>p z+(KSXn;H$IuHlW-%;*BP3y?ct#w4LxQevc{?Re<=2KiTrW62ffazWB$<1~y|@) zT1APc2RZa0hpx;tP7ZYoe2^eNLkThz2F_m-p` zcdu%cOSZOFjbS_0IGo?Q*O6zj0*nM&YBUwX65dDPc|}J7XH@B{Lf*0)9)oYOGS%AG z9+t!W`vEXeZ=-M@h=V6hqp+(9=tD(L^-E${%-D1o@y(!cXEQUjGn*l8yg2nHYAY05 zz6a7=xq3++3(y+&C8sMalvQ`wHNGPqt=a! z6!7@PY~?1IeF@ewX1NAUyjOAvzh`bo)=-gL!BEwX=o1R3rJzxo9^M1y0;Up-CMg_b? zCrfM+IF-}I7))oK-$jhJEha0ci!Rv?Wv<2;)?FtJ^!2qW2ZqTS%|W&&Rym^!tmVJ9L; zc(qsLQde8$!G zrp5KqIP>zHn%*GF=bxBSLSu3?xj^Z|CL2^KUlVd8KZp++0oO7M>kL6YF}d7Ms%hCH z#!_W-H!5)058|C{E7n?n-mwRJ$(Roiq-h0mMy4gu1atRPna70c5?}ap&XPM2tDP;` z_hiV@l=3VrKb0+eY>i}?Fs5lSW1C71WR)=Wv}Orb#NxzD3|7X-VzR@XzK}?f@a!o{ z4n#<_k)rBiPSp^h4&Gm7<4!=sKej0YkCDmJ`9jAZHJz<5LVMCnsTesv2A>_z>5Ls8 z1B^bSDJEmvUpDQKrZac0T6p z2z@YVncuPk;5(9nE{rq`A6e4wGeQC5v{{h)PGn0c_l>evTY#RRzts+Q?isL zdBB3Mgo&vH0C*43hu=f8N0zPhJ;DsJ;KMXn_4V$Ym5mGiAOGHR6q+3^dQOFGkO*tX zAgoeX!})S2Q7+I&L~futqIk*@+F&5;7F8=}(|Iv#5mV!Ii}PAb4nAEm4Q9HkA3}>+ ziC_rMA8M!I0n56ooL67df{_JP3U29``#RdIt=R%6IbD*3Ld1zu?GZHSwZ_u1PMDDe zh6G?aFLXiJ;7HqvJa0;-o8Ba7hVUyXU_9q;((PXlM(R3MPGq?0n z0aa+lvME$Uflv-80fG_F!cWO{G_pb;a!gLWJEf%;6ju<53sL+XWy$1h)~29!I$CPS z>)b8C3gKNjU0DbAQjBiahxomY^=-#dts89F5fYI}$`$ySm*awElBQ#*;(kxFqb}Z> zbMY+`Gd+Jvx^f4j7%))9=qdSSwngS)GGBkGCgcJ+ASV9z1rL~I93xHl*Amb2cP9DW$Yo2XCojmwBt}qfaVX6-b&BaeLO_)~w?- z|G9Mx0G#lWeATQ5$IF_sJO#- za3w#;S5ScpYcFHOjM4?8c_@ZBjL&AN!#qEpzkhf6?k_LN#hi+nOMHP*lGINJfjnuV z9X15;a$A(QrDZmq@`N*y_~;lWG%r{%zB9*(HHGfLMlqKU0GVOP0d21%0>Lji%VmM^ zgr0}NIAx*0WCNi+iOh4XEvzNEV{Cy|HCV}();(ZEUS^svGT6WuUwsMAN@awmf@D(6 zjNb30qJk7<#)zY1U9m|vCTU~{2>AjU{%`W41^X=|`r9Bm&>QiywI291WM5w0VGf+MZH_C9@gC!F02a19PuFd1d!W9EHTNY8h zaxXQHtT=hpZoO|u4GS4l*dgiM-oX6zh~LfYX>99*S0d4uN7IZ1{qUnj)VYd z6=v+EP?|!)K^VOuZp(!Y9;Xh|4P{#wR3Ft<8GP9IqLg<43fCh>Ylb(_X!LB`g=b_R(&XTOO_ ziK^!Gs*nrv(R6xS@+@V=OM4_gB3-It;Kws20Fgx;Yj6k|x!a9;#`V0sg`A-v_CoQQ zIt$u9L(9|rFT_MQ6-Gj)2^tVJ4e^WIowzmqf)myq3^59);^Gp zMI1Uanpk}^1CXCUS2P2%u?u*?QVB_k@Z#9$q)cdt`tJ%hJgAj@^EjxLZO?(ZuP(@e zx&Ny$_k&t_P%95=?SP~_YY$A?eL{N7&VQqcCwFgth%)fK z`ACE;+7=XI7cJpyOYYWTnQzD;DiyQ9u$n1dWdN*CgWgk~fmBc1C|Lzo=FsA*&Y(_W z#;9tGtLz~y*&wR1mI(53B|O+3wiSBRcGzN)N7^rGCTDLjaj}2k-^!WIa$HT+Yt1z@ z4-;kH-1@jpLLHlNP4nix9Fu>xVORC-lbn6a?pe$xnYm`>-ThBBWw&KB!y1E#*Yc+a zS~M@h81wKpS)iPEpx?z2?J!Rjip~JLG8eA^+*eGwwV2ly6r#Sg$0`V@ZtleBX+UI; zZJtXF5G|1)`D^T!3-bQW#n)ed{a^0zLT$GW96X;GRIrR1eZ>%8mpE^}8+r8c@e4=> z{c8U2zsnsSyZgMQ^-^$~tD373Q6rL%$b3Z75qTJq78S8)+fbx&MX|RIhYz=KZENbe z$6Atdkx81?(!aEHI6*Gwua&1XC^C+#$TQ6s_9s_zagwKJt!*_d!y68ko(8EPsH?JR zEPbbKVN<(8H(dJ=n?i&-)NMaF<2zGEmH^Rr@10V!+dMGXtKkstub5b?R0 zt*iY$XvbmB<+Vgk2j;S3+5o)`Qasy{0s<}7a6ls?eqPy}MR(z+R@j!R%7MjHL%=VP zh#i<;>j~;tJ|dF;GRnK~&EuIlphO|+2F?wO@&tu`)yPpaBZ1dyrr^h2Aa7O89p$tH zUW0>ayJ=)7eW)voF}e`$~jh50V0E-kYq-62N5A_atzP&Qq$XvdB{ab1+`H1 z7Hb)2*jJgj_U1#Lm?c< zOaCqMNc`ZI)g=;|%Tj=y$*6v%4mqvW@Vai*K>esDY@X#*&>8d9=G3?%-)Gx6-kgMR zIIf@LaeeRPyOjgWMel)iguCm+UQVkXxFRy=THES!0Ve^En1e_%qPD$60BA=+u6IC+ z*)njXb#x2{i3hG2Rv>9B)rf$M)fg>eGy9Yn%^rvGncc{q7u383S7Rsy7^y%>Ny=xe zHKJfEU{caANHoH%ZZxAFlvUD!w7Tm#6*S>uwp$CiZFJQL(c(2~(-c0|#)h~r{dVhZ zjTg4le&YqIQ(v%83s!Kr@R?JAz5qG{V47Ij&jQGoi$vy#z6`F_mgddd$Q;A`QyibCDzw-No+LKHk6{ zA+oQb$p_HvwfBS2%b4aXN#55QSS&nHEppS^2bk>A()2Oj+p+Wd^;t~g5ypct1o}E9 zpro5?V3x$b1#$;(56O-&TL+m!*olY)5{L}xp7q5YO=YVO#J$%`)| z`hU-ovQYeH1)OW+sdpY94vI&^d+^Je8sS z$~1Ah^|=~^^baez;%0KHlcNb+kEpNY!TjOnY zqhRqyp?A^dWaNwrtkIGBOBC$Sz;1B+ksO6Y!Cq*a6l(=3G*5FZb(hn$+m9K{y;{Zz zjG(cvig>K_wpmXjbGkV+P}O6xfyEUeE(|ZvSv9QAj#h{4$=lj^o5$pb)Y(h_a7UrV zea^^2T4Bl-K!o5KmUfgWz-O&Ci<8Mg6mv!YNL3j+;&k=wtsy7rV>`ipS!SmgvuHPVbo_isw9|MF#m>*Elh- zlQMD73n^^Loq~g=8HDEikCPwH-~Z#?`P?b zUGT@?>_Qu$TRX$aAKbtG*mQ9ElxFN9O5N`u6|Zd?Y)}N3*_qo6Syz&1LSBR8!3b%} z>IO8+YA<)VxIw`Rc#iXYz;dDP`A%M&ohXfzbOnT=`VHK^ck=ZomXx~nqV-;~4v$&v zihaYDEds zQF7`CkiYeH)u0w)JQK2D>1ja0{r#MfKQEog+#cw|z48YJC_6@bd9uowk5_go3wF;6 za*|4{jegG)eL5lkFDqoHW+K=O(<|*IbjnE}dw)qzpgF?xoTXR}`_!pRYN<49tySDz zj}@Q(fVa*nim`{}2UpatS~T=nubc+USq+iwBY{qP$V|?b*9)UCUr3>J0r!1?#I%sL zRL+ra=`G8yA!I}rafHOp;K7i@CbR|&UQ0=4+HSWV1li81^`~UvXdJXi+e)|XcYFT2 z5vRWsE;pd#mFqbz+OB*rd9F=j+gn%LA7?NJdnFfXC4nwv+97cm$vhByk<`L4ZM2Xq zfT1SV=Bj1oPr#%EUxwRs)J}3?!+1dwSrkkyq`>N8?trHAA+I)sXt~`^|k0R-+@X8RbkPk9R3ED@%-JZZq>Rs^JQo%$@%JT24ljR`oF+2 zuv)jp9Z(~b%to#RvZu@D<({rVmb3KCh_t2&Z1w3te(x%Q9@nKN&_``EK7qjB`}QE5 z(QX;LWm-{Sy>fuuO~G_2r%@Y*Pm>&eDMsX-)aE~dNd8JP^-gN|%}!Sj2fL58vm%^L zyE9DREDjFJtx=Qgaw&)`>=HzD<3${0J8?RnkYem22HPYg(^I&#TXkqV0|z1g1&Z-5 zGMX^J00G~PSplQ7bOMIECuhZskp->MbN$>xX1?7dBkaMEAm}RW? zH)~uEn(66ov2IMDf-uZ2F+H!!AVw*bidjHetN0$>vE|XIx8zDl7>+K*(a1+>)GoSb z^x)7tg1;SYDz-$Nz=&6dV=-1+@J&auW$f8_TWifpN7@RvmB65aV0x>pDGcKTQ$o91 z18NEcLt0ZnLbIeaQj(29gvNbhxKVqgyek)O=UkLdhnQ_6GyQl$Z?;EijM_8)zS>v} zHm~U>9agMx;SYM%r)2b4es(H`>IY_Hhbxmn%?RO+yalHBs=wn-vrOL7%q5Yw&**0DT|aXBW5)o1?eZB!aG=eh z-6&mpER7+N&|3LGN#~?3-XqWSNQw(DZDXP_7lw)85?1k{MX~3rC=nEKy}6nATVOMf==-A!a5o z?0>(q|NWZ$((whkB3HHln*VfsF*chLEYXWmosiaWN9-8~c8Ws*T9n9~!BTwnKie5L zeruZLnn+<=cyR(#J0%Zbrp)Ob+QQBgUDC`9>g4P3i&G*+?e*4f?zuD!(aq@OMMt2* z>eRn#n0js2Fls86FqGkR!jXt`v3#IQPbi#xGUNA*%=v82iXf+@OMI~Ro;y?#>}*MR z2MfK_#|n)4s8-qZQ0LRLP62Zc;EH_dygNPM2!RLX>#sKUpyd9(Z_NsPOM#1?Hc+)y z0@SmsJ=6<`i6@kvEZFtT3C^#pljNT4k?nI9v8pNi#5`%)mug#LpWjrcKkVVU9}?P?3(|8MLq-h`8XHCkB&`}^PRlEHt~ z&fs^#q4B?+LRxit8xQU8PO4Qng-D7u3Q-SK?bu)^vnZ}hpdKS4*n^EH4wiCd$pZDx z@yqrLbjuQ2D&{avQliYZI<@xelds8`e0ge)xWGFETN_Frh6~$-Iz2b?y;=8;E6X)D zzak&(m!Aolvh(Sb3$B+}GULhCK~(S7S`7HxTt1KohVz8IHY<0mYQs1)KlGX=Fv;67 z5GxL?deF_DO~`i(j6$SEN2<)2{8b8ByhKUT3_(?lqjh+eKqXn3A~fI%TkD{sV{!?a z{mZ`Az5Wl8@~NkaU7fa*Fc&bsPQ!t4bF?JZt(Q=S!>kTjz=n2dYoRe=Y%%ApWx%Tb zB(MfR29iwKrGPkFDe%N}*%zi6-88}jkNXWoRP64shwXJ9b>L#$au8~TB^*i+8_F$E30vAuG%j_S}cu4dNJ2v^mdFuZei64FAyMXZiUA+c_? zL;q#HXCtV&UVpav$s6?AY{%I2O0OAfw!PTv`cR#DLGTx~Hy9(HF%i&V=~!D%hnCFN zLm9jHKur%LC(czsG|MtugT<@0Mv~XE(rdd6N@G&DYc)0)Hs-PuEdq+eN$v`G$hA=cH&RMn~1xw4Ms}h!ZREH`+$a$!NBe=99n@6=hK0;hY5y#T`6mGUl z0%iBCSdxXyi3IvjmEtqZ{F=I`GEl@|epZ)h?cm5NIY(eQkx?}LY0c?hpS|cZr*EQd zU%~&p9lX~bemQNryH)mcc#C380h6Hb@t-Kti@NSW>o@P_*a1~ z+<$3D+JWm8Si>QV3Lz$Bk=jsjySXp}tR`oKf!r}^#B1}nxm|4pYZ%z@xh7xavS42X z%{&e|xo~CS{$RxCKfe5fS%tJ_OmNO<%Gz>8hJ^n0%D%P5`o@PgLDZhr3*jbFLfw)t ziJlj-oXy*uOwSC)eFFe@9bFUYZN1D9vy6tV)Hbqa3#wbg8S%T%tFn>KR5UpD&9~RY zN+w#uB?JqtA;#c2MyA|6{r*ZtEpX~Cq!KG4a#b7>0&^t(uMoRg&qS0C)L!guMPX`Y?1WWNspfe*(im`!E5_a*qx@Z z#1s>X1Iun4d{nZ_Q1EQ`JO+ridmaHyyXtBvsJ35_9fNDT=P5w8>vMXBVB78)lx^1s zzU`h~5blb)Ar5!MN(M;Xy?EU9$@M`Ek{#wCMJ5+*lD&ZsRu>q+NG#rYHy3$6d?KO@ zL&RYLp*Fr8gL@8~=fHUmoaa}~dDhB5L@edMJllzAKB4W!B*^N<08pTf7`Zry8|wlS z0vr?%Y1lENp=>PT(3#Q1>YHeI3UoyXen7YYykMz>q8RYv*yyAfq|t7ZA_uiHVjc&z zvh6uA_tgbCF!z5I=6+Bs4{GH>tz3Qgz+x0{5fhgj^kSQ#l;CTR*%%UVrYS3y^?f-?n{gWKk) z@{^nESAT8*_~~Y(vee&AzbjH!-0+am=TrRnF) z{%|Wxkt!Q_>EMM7;c98QU}|AY$v}nd>sNm!IsF8y)1IGu9@9BgWS%jlA;~@LfGPrc z%dORk{r+g0FT7ykoBiW|I-~NfBbK9|JCH{ z|C+SGXgtrD&5oG0vIeU3p!&){IOS| zf&a$UOxsm4@SZ~8eOh5}0q|I*XwQYeBa43b$~>{fzGJ7o&m!Mj7Wm#paqmqEdp~ti z@1X^~`;lon1oxd4@$MZ(U-9l}aKk+p?T#+k-LKR|7wV3k`<@GQM;7OPgu>j9QR%tVnb03Un3Lj;@sZ zm<6?;Wijnd3u*7Bi1v1H86AbQTZ?9Ih=GC2vW3bTt*zRgTP6Wk#D`V}Fmgi! z6W^VuO6>}5L#wX$Cs0=F<;u+VrS6h}RSau=Lj}WTBfFVmk}#!^2~x2Pn4rDa3)y%< zd#hzWsMi@)nkRqGWO8TbzBLM0Q=7Fl5aj&FYr`<^%(6qlN?d@I3g@)7i@WlcWlSF{ z&;&_NlQ}}fStxGyX(6pIpks0H8R!F3cs$PRf%*-7Pz+~#Yi4Wy+$NL7xSFS`9d2dV zHdL)SkVCN1K}}wCVOn#TJ&UjdOIeZ!im)9(hPqv4H+=DuycVh~SXG2@wVNhc6SfWQ zaFF}mSt%Hw*9efMUXmmBN&oxNh#Y;ID)S$qr|M`zF7rjk6RwR^DWrZtJ{PLU(Tk(*)~}tEGz#ZkwK0{2?+hRvzdQmd-}IVLK{7_~nL`^f^kj)K2puv_ z9JDrxg4ZSyHWf1Pbh!3h)$O9RfGJanyn$7(D5kZA)~egTyE=H>+Z^Y1$Hp&T?P?KS zdtjXu{HKzU%U1w-K!(4L#xGc*xYCBAq&2?Fkr|(y=k#YO$m>5}+lD%i)6=YIC(-JQ zVi@}c>J-^K!Wih!Wx1Cu=q};fC z*g1zC4S!#P?3)$oGEPJYaJ5#x-;HQGc?6*}YT56&=!`M1Uu5&PQI=Rzp)!JYd_AXz zmXf^8G+#7=ZdMPRdUM90(2+YpMrQ>=MP4y9pQbNeG1}fk2q(6&vA0yvnQ00LEXnal zIOqK>o}kTH_|I(M0LF(ZrcWm|yQzX@*qR{iOWWZzP7)7^wJVZyOUa;Za|D`^kLxq+AuvFv zhRx4?;iiY=6n;%Q?p@@N`tNtO!0oTNF>ZRt6SkO7vuV@P+FyI`xDyNOKt)anXh3}Z%tC2aH<}Jbf?s+CGq+c28k*xa_9WK)LEs5O@Y^AOP+22_&rH{^_ z&T0V#`dvImJse|D$i?cu!-K)CU>% zAj2MH*k7XzySMNgM~1NYvkeie;(d`KKUY?||0tSXh~&Ci-ouC1rBeTE@WR+!g@s&{ zowZr9emYEG3o+7OqCp`uJ%=Y~vd#l@^P5|)EAFP4CJR>N9BKzbIDKN%azKVO@}g}n zQuY)?Cfd~~C$~&LFeb>CUw-)|i1}as=YReukp-b7WeLyMUxc@Q_oAgXnS1{C`P*+H zjD4XMxs`fudo>@|8df9nzplS~S7AWZ{|Y8AzbxH-hIZpG|Ks2Pz2|LSKxtgaYOFG5 z7B2fkNKGhkNhg(KYL^k;dcve3!IjVE+SYqF=QrbtMs9~Z2RGeiC_q16v*_{Wq-;bo ze#gjE{iTrQV&v1FZCZmxJ;9EuGo`vpy6-w@wAX1fE9!|YZ+=%Rrs%?+Am9## zow}fu^k67e0LCueWKqa};vw)DE>1mGR+Dqp=qvwfXCHSA>&+X6%rIpVS~atPvhpj~ z85su%nLD=hs1BX&H;lN-qA}-N;fX25TFaP2+0#1EWf&-hx$s(+4rH0xltKr@Z+FEn zZnsM-L_lD=v|E7*o2AH@QZ_*`r^OvhJ^h?OHlT6|l|3q7MveH3rVYBRK_>tp#$Af)p$A(XS>U~!u+>qY^P|j zc@K+i7+4gXa&GzTcf1(U_68RW-a+EBc4RJ0pFqk8tsJMq~Y z2gN6rkKz-@P4VfAFu-T{1#z(mxB!+gBJG>{g#{ZYh~SP0MBNKZTJdVoTP3qnW8*_U z4=FPYjAab+i~Gp&YC{1f2fm18H?EavQnoAf=P}H+n^(pu&3g@e>9dB#S;B@K+u;_l z$FY7risfq)tJm%=UQc7~dd8NnDC!V{B3ru%?gO8JxN)@=5c1;@?_-<;5yWS>wJuRS z&Q_#2Il1tO@h;x>QfO98X~IrJ8xmX0S7e+)u2h>6WwJhn-^DGHnEV9nnv8d%1GG$lgZN}C7 zde`2jTDN5z#9Oif`&_#@+A_3t06%o$e6{4y0~u3Nx|n`HGYc^ zVpI+D+waAq_WOipS&#Bnmtq`mK)t|iDkw@C;0mswQ(J)}Mri3tHrP@^ zc8=n6tqXoz>TW_;!Dn4X62{1_9`4z$1`LuhQe5ReYs3~OUTy@D z5r28CNGg*OFzNl4RzY%Tw(Q@W&chv%l-eb4_4bg;2Vp4s`BiIHe?6nWdOuWM+^>oG zJ-wBsc6p;6j_-9Z`SbOLH<{&a70WJfcV%)P-1@<}esHcgKfg-n`XzeL4ady50@TAA zQE?!l-HS8SvH7YZXQ<$;=F@i87wD+=dMyyndTgVi}$sM^!p{*V*wqef4ReJ3; z)PBPVfglWFA$z<6_<&GDg^MzzT9qx(M4Huns0 zUK4j}x=@Yl&w4#a?`|_ErYay90Yy|jRVW7BZCu$sOgGNSML>|6M(<*D!BetDt!=W$ zV1rGA3`X8IUl$@Gx;z9K9D)qGpFIZ|1Z?lhh7zpD5=5+7=#6k82e-`0 zAcmP1^~kQ{$>bPgyDBB3)YI|r2@{D-W6zKoW1%z%MwNLmjGoBdcp>T_qEU=6gYotA z=K<8(;Xl6FOst6_e3iiC(I)Mpc=YO*DA%~ZE0Xb?1F}*IRD-D=A0|F0_}L^`lq1{3 zBxkuSmLuPc`D3kJ`vxM;CuLDEp|fQm5banV@{{hv>8YOjovK`$VEy*|7U-zWW9^Qk ztRC-0Hs3OFPwr{aSm$f~87Km!{GKb>>8-3DDwf|xoJ9gM#1I-*|0a6yjrCi(EmnsJ z_LlJ4qaC^Y4xii~{1tihMW4q4pP=O7hu{7(uF4gje3-yLzBv8U=`Zew-=3bHoc!&Z zw|}|0di{5P`pe%$ncv}0znuJyz5aV-Bd4c-YA%Gh`qZQ`F7#LyV_f=|fbkpAh+Cjd z?n}jkDwKIALGR(H4-tRefS!x=8ylbY8APA;jsP58ulUy4@~)kFW|C(4LKd`GlGIwf zmd^Uxhzhp1x&$!1l(!MaDA+NU@-p8U=oqvXuGRxo46v05T)2&W&6S^_$sMXhemVQB zfi?X1qazytkuxg16&V6uWXg_}e;2!rHtM3c)CP;5*hWr`VEGoLioJqo_iQbR1~%e9 zvu};G)aioiW6AN1IGX(qN*;HUa1l&ef--7B`=%t53C;ZRstHYSuwJ`+9OE1`$IJAH zQYM&CGlfwzJb|)Cpwz+{h&od@P_*F_&&!;Y%8XEo`uEiUA6!Ky0EFWLKB_75-L!em z$hBXs$|{83eyfS95>yvE0xOQoDFk(R30C>SHG?jr;931Px{4uwF-u|N5TE+~JWI)H zLwTy7Bf40~ty!XLsLm6^(jN6dO6mgq{Qa~p;MOi~yursZ(PWueEIM8*_=DZ0whTVk zWNiM=8HSu!@0Lw5h6%p`wY)=#LK9cUG~~50UwR1xs&aYXU0(8gWxcMvgQC*YTE@6S z66OU}5x>stgwxq6%i#9YFgEnG+@GLd~TH0|{NwgzL_H z1YOVs>bZjl4@THNoaEFdScDs0PZiYjLYA{RWWV8CNk$bWC$>AF8{4&NydvpR(3~f} z&PpNgx#H3~ilD!)DN=IfOJ|_h>LQ~&Cnt(A^4gtu{L3{e8EDq*j-Cob3#G68EG*!v zGs^}Zdbq`%0~KlWP&?~BniJVPL0LdhpQ{nYL@KLTkJk3iuP#++kHA}KtB=4RGAU*u zJgL9Kt!*0aBcKN7Jx@!TA>Zkq)5Y~A_Qq#(J$_(d+C@pAB2sRQd@bCWD_~Kbjb7R>PGh`?1}pJLYq3Tngn z*O4zPnqw*bZKBoht3!3e@C{+1iNvx zUHD3wMqF&X^MJZ}%hEI`OW0=)k`ICv?sQ!Ja4{l$!Y1w~-;CooTFx-h!{w@Vd$wgd z!6}3`^swEJe=w6XfBob54?%6LKSH!(Pw?l*l`q2V0biy4v z(8Y2>t|Y{C@f5ERjJaU{bS@Xz7H>;VsAdA#c}s1~>al6)&@>PT3Ttu#W>AD!84)cd zkf~0}X`XXI*e9+4zYCWZc81!F1}E^C9?fQZEVr&uEdo~mEF)hCslV{2+eI*fWFrZ^ zm)w;{H6%cQpP>iJz;4;?lH^=zddDW@+6X*h%mi+vAW)WxrKA*^x97+Zt5*2_VHpBp z2*3-<#IW>5!NyMP!nbcM%n`S4EmgqGU5ccVtzcu- zguDZ>DeFG97_EdR3+s*&EMZE~Vu?ZBT)S|58|!Su$Lro{pk9`$G7}6MqG=34$c|^#hdj@(c<2)+v*)Xr)J%*lMNBiYAISo}0mUY?C7#}!g zlb;zk)G%&Ezo^M;R($ss4@_-4aVC(7-FAn!SAYF z3?k8$-D6Kdt(kf}+)9rjj923*WBMHy=>oC85aAa0_GTo4pt%Y9ar);BesD5@cl+Nm za{(*Bx45MyxZGhM4bg|yDgOpaxmh2f%U?IV=KSgsM;71j8@Sp_E9~hxFVgXX7J7+B zo>6U7K9x7J`N2UjeMKe1r?!=_B+f5q9liBkiC&RNxW4KcJj?V`C!oeJ(>PBElb)#JlZqyXi>8W3feedi@uFk6_G zMubldgOy?oKFX*eRE{DmDNk%TGnyNKiUcDGny&~GIT5`%H~0WS!}d-wqP)d@a2tmP zNGfh0nkfPz>qHGMQbWaooq+*El}Q4r)6}#Vto*u(5W}MMkYT!SM9&Mx2+xf=LWL$NpL$#n=j-g+qgeg!NAQjZEuo<^%jAP1`ayczQROPL za1Wz;hmp+JwrohO*~@@7j?DdgU|DAV+eIOx@?IL}#%BW4@VRmpK$}-{k`{8YuvY#2 zbhEiZ{6=xl6ome`d>*qkGbUI;HFy;*2rsa$)q%uV+VB~u1NCe)x_O&7*1co@8aX~L zaF5;Hi`+Co0y`z&E8GfC)qOrxl!j|TTu{l4?D#xe%!8goebFbM*4L#rri(%<_0D~= z#hf3l(yQ}C=k5|x||56 zEpC)E5x;l+{-rQNj@2rHJLN92gA5CL(GodR6+HmIKUUUXZT=1!x1?6OU_!2K$k9sY z>sUD{)0FqY$%T(&A~!9JYp+a#{HjeGKJ9B?W{E1HG6=*CqsFTjw(+E0PRVHoS0AuzM~`wSxzqMq><+)V3If={{rDg#+vP2=CO%1#| zHC({6oC-Q)W8eL_N^v12BK1G-?P*!PN|ujzU8SL_oaN`XKdy+( zxz^0Z$@;4?B3#$f)$L^mJ3L0bvQNISa3wrP4+9j{2d+>o7KG;uEbal9c5G9`oc-C4 zIDyzZ!ajjl00;G}r6Yr0$DH>#5Qf@8bst)+IC{%6@>9u*B{4#uOBaX}(4a7{;wk1p zIDgJQEJonSdHu-t8WfMH-XdR3pyG}jLiTYrY0I((u^ zsfABlSv6cosH-$=?!@^w-9kfhvRRC%`bcWimAECQ1h zYR(s~m^j?wp$7t=A0WWib%>hmr5KTSQk(z0hO_}VaIYj&@1%y`Jj%-BgdTId9F#0|>Dssz_S(3?%$^mYW^Fp+U&ivt>B4dxls5@#(L) zR)5=_sOV1yYloXG;trM%q@8aejpcFl(hbhorlcyE8;T$~T^KU;e~hF7xB34t$kXO3*`V8i)+IMmS{TON%D0F03u z@jJQ{M-|v)jevOp3_R#Z@VBF8(R7%|xles&+t5I3K)uK)dNB57hF|TcsmRuK@J{6^ zvdNB5VnYVZg{X9vL6>;7jKtnozqP|46Vs#cn$`ZH>4PBol&c{dvR<}302l}}Dr8|3 zSl41gq2gCnccZ^XU-eWm0|iqHiLsN76SPvx9Ez8_$Sh43WwDUTmUmh`$kCZ2Hf_h{ z(P4_HKiTF!cr4fR6;v&B+5|{JLN-qzYAi0u50xPg6obRS1l?nd$q3w1MwQTELLKj7W^b$N5LD70om79aa02Ap}mckw(ho-dsLYSGklxp9#J$ykT5ucj**<|S0 z`PBkuz*$|`YE;YSTM4z02wLxqSdMGnyd*IN@7-hL87aA9cmtHCnvJm5;4}-WO)!$n zluvCe)^*^|8(|K-O=Az?Y@>!SWa+lTwHjBHVhkjlMcN)$qs5xt{msO2J1_qR{G+eV zjC(d`7yuydaHDDvg;k{e7JT{#AZv0;-c)rLxdIzEcc@b4B5;vprFBCil`=GAPpi5S z8?HWea*d18_wgyQmf2tnokL`JXhfZ0dNoH1(U7aLw_cudf>@2lcumPo+Dp;`v42;S{(y}hn1xy-$bjf;T8GW&ty z+<}}CQw@ABA4n?61B1vJBLqTpw{pT{FhfWsN@Tt$WX^q*u{{;N*P!QiW@Tr|m^#XH zRtmF&Rh5l57ev!y#r&5&;(3{ADwr%)cZurHV*C2Jea1fF)!P=9wQ8v@ z7(gOV1&tXk8B`gK>6w=jJQf-I#1ab(vB=69Z$%W^L#g}rTJ}}3?ozQ%5Juwgy!tT$ zpRV-$=P9$?G?$%E*@B4_s$adSjw-In*2{0JHa&fn-D6ijs>Z?sb$c$eR1x+`7u^L+ z6Pf3RT>AE=golmiE6)ILn>^n#owpwDkc<% zI#eO@u$EAu*<&CAxwaQi)nEiV8%L8UpAsQgMi(Z}c(;7*m7bGsol`l2bW;JD)!4uY z5>xTts-f64&Zc`+>`Xgeij4w_N%*oy|0Oxqug+; zgcauCWJ~f;$e18QRDjRZ)MiOqkWK^;m;|*ypq1^nE&B187w z6|0^7r4`NtYh1glOFBO0FzL2eXM1>8YlQ={}S55E2+P zX((Ap4eg)6gUJ9D#R0;S@gJ>*AZl+;W#QJQn|aJ#ITjb!jP0jp7n2?^=BNu`NA&&o zm#^YApz0f^B*4Gx%Yi4Nb9&%;TX+Yc&)+u zz5C0>Yhr&}SBL8c@z&;t8OpnB=xkZ%W|pwZwVQHv_Y5uXs~V`QHxZPKS;~?;STOJi z?e>N*UXs^Bl?AIR46Sx!1k;`9x&RrkUOtMI{*jJ@UB+kS5?IhegO0wd6X+XsR5JL5 z*!BosPF?O)J!*q1-#`@#0Zb_Nn7#3(RmfS&?$1<8UyNXQE`_>27pllnUv2wqp7V?r z*|JtnyK2KQMAsQa6MlI_PGkYSCRC7&Ian}DNR}wOpFW$@yjvH~BHg9zf~^JYwpOp> zRmFz5FuZ9(zPH@NvSr+HvjFam=d$Wi7kh6;rxo+j)+Qpd?sR)*E8T6r>Q{L1ByKFH zas8exm{puz8i|v7j zqWXl~ge8K4Y*%ZK@M9QR`rTnC^aUHCYycJHQgB^W@5aQpObQ!WWm>iFlNr|*!x=j< ze|D|4c2^ZAfXcFdkF@$>g2HlBszX%F_S%9rz9kpD@OwNWEgC4L-zrpzVF&%do6^qoe z^n7;;mY%!Ss+Pnn7rG~r@foekql&0&ONG_~xRS2ISyjVp!HS$?-q^ln*S)R&wqmQl zo9%)v)onP~y;RqbzpIXG5xeoOojT236m0AZ#7ubx$v_p;4@hup!_L6ytd#h5wp=wd zR$?J~1Gut4zFoELeCa`J65oFz0Hg;eKNjoPF!eyeVYI#sinGwZoah)D{;{v5g9_b7tUN5KYIs*Pe!E zEo3Q_sAZmUaX0eCiKfz`XEI{`;0}GkXto)%+3B%~WHfq*7Iv_5o16PrM|jZC5zQrf zVicaml111wwjljnC5mrL_o0y*(HG?M`r`WXIXju!cs)#JClY!xr;GDa&tGu`_@VK_ z)!LUqt`^ouc6HCVS?2EZ?%TNd>-iO-rCB^}OG|DkxKwkz#?1b~Gqm4rF+bPBK4$lr zVXX(JVEeNrA%-jc894&E;F?n{i(UF)YK?lMQmM4e@s@!F7v6y2l3rA0F!TrrOsTLy3QkTJR4B7O@oM_9 z^%@_O6P+wNovAy|s>@0d$}BjC8{DmLeO6u9kap~Hg@e5_bDnL^Z(lgQEBG7vmMe`3 z3-~fb$YM5=k>IY34$K$-plMpXL~d+#6j^k~G;`$(aZuqS15WgEVarF|TwFmbiv0dR zz66o(>#zRf%g+7(EE1l6y}sUkWe?Qy002P7$Z^*gK5wYFr7du9JEvn#k>^SAlHeiu z{Sf?q2!8+d1;4v2Y~*!2GdTrq0;I`0TSbm~_53;NPK;0dr#9j`HWF6r-@=95)OgiJ zl4CbDj6~~8hOKf+U%k8j$G7Kye*G=1v<+%Am)UBHyNr0=nrQUyv)JC>E>=A4g1mck zJvF`rL)*93og~OaTD))x%;K+VhBJ$ zZ$fSn;0Ksni8Qb<{K;@8rj(IjauM7hdCHH*=rfp z?LL(j07fLxPz~9a<=eRfx&eiC6_gPG(6%Ag(7-OOroO>dyp6V+@QrIpsB&U~4T6mX z-*~dcCQr@_e%ynpV>f1weq!TK&Bi2UF0~XJP zOjru%r>(nbx46RxESY^c(c)qw(*aqy=4H38m#?f?>(XeIJ!d51ppo^%ws&bDy?nLt z-IRrXki`((s`@7@;c@nFt4Z*!OYnJJziYUDD-~MXuHkdKg^z#x_Qpy-V>lwb6a%P| z`@kAy%-&TriGo=!xNZBUGj22+)0#s569By9$c%d%on=_lFw4xYND)>|w17hG2=`d| zFQ*HIB{fp{ARcIulJl#!Xq>2wD?EsO_|}7RuBs*>B-f&xGjhwds#QM-3ca@(o@!8w{HH3s_1nGslBtVWS%X~=#otE%9|DIXfVQeUhDJ9w~E_fYl&3! zg=SLBVAp#5Kr)QxW2p~sTP}KhT=A6&6HLyyDN3dPT#7V{KzSdIoPV*_3;H~*85_(l zNx~HF(#Ht^+3V`_4^ z8t`gO%XaaVFUtWjSmWDFCf&Fueu->dE0GfTh|C#HnJwsOM4QEer4vFf%uSo}1nP;J zzojfKjqnR;;}Kom%o&kI%CKO}6x{Q^!GMWC`VW*3yyd!}g{^{W*FB;mLy54^4zve- zVx8XZG)?ymD|iZL=z2h5;Y|y;VILr@t=}Kzh_FuP$Zc27HX$gz)7YYI7zqN2-EePw z1SiuIBjf0jX4!JgJ{j6-4nOc`$j5fIeOPo|NjS8Nf@y>fJHmMg3CUDP*dP?@DK&XBC?_so6ZVYV$^Qn>VW5yxD^8WGOeO-@I)F=M7KZ=H%=N>o`AY zCFiHF<-Ead82rI@6`kX95b)Vf4Rt50!IpEobafA`I=HSaMs@}|WuSjTb)-mvAEQ!{#TbSuyu2r>J z&&W&`7=>fGK#%R~#)1qXLeSJ!XF)sm=10$GFPEaKmp#-3J8;Y5Wzx>r+11{om?3(X z-_pfEM~(lkR^W%;%2K;zZ~S}2azS+jEuBwm$A;qpYR+ai0UiAH0F)77G?^PwY>duk zBPcqF@RgY_N@#MG`^27Hzx?jJ1_1}oqv4{Ml#SD|@}a0gXd`=bhBSNKoQVo%272`h zCaKXXSZY2~gUY9qrdd=_2IlPBAc#_|^#O$&I5DcC=vs(a~Fy{$CKbc1DyKeXV z(#M(!f~`=@h#W9nfU_|3U`pAN{y8n~Sn9>13Ar*8cD97b-U`RAAU2IIYXG)pD94k@ zu?5IlhqI09WRT&YcBkIbg+gQilxu}32TZJ%I0CLYGNBpclPZ0sM`dm)oLN|jzhXGh# zj!{GOZnF2#pw(w@p+c)qZ0OMH6BkOf`ot?6_-u0tL+IP0rma}<0+>JOW{ZFz4ZM4n zmEiTGw@PNEjzQLKYbfMNFj!~Wif2TtO$OWyBnMJo6BADCw3|!d$`PJn>Q%mq=i?Jnm z$3-r;25b zi*Y6!D#y@%54_mwQ!h~e-bqc?n2dI+_)+5{9c)kf5*?9L2&pm9XN0bbj_jJI2OTv* z#<)lgbHYen7e3!v|9-VM5%|eP8Xs^=IR7l&PD_R!e(TQ?raD2o{fQNEC;A9A1GpLmG;Ik9+q>%d%N` zj9e zD)j0J7@dcS57tWNOk}dC`(KVHlj9-61CDdzt>2}dj(<;>NMs6yBw^gez(E?(w=#Q# zHpARiJp^mophnS;1oIm*!Hsy8%bQJ(LC6U?6ppeo5k^QL3kY z@2h&IU_tbf%3vvL>PuRyQDwO>zh&Z{+|xo0yPR8ypeeuSYIu$W70d4iop*vTpBqu@ z`qvwUeb+Yf+OlVKSIAN?N^Kd?;H|V5&sCrC7jERWios19E#yUJ3sy9Z=%fa z@TXr+{>EPaJ+hJ0(?9)>fdj2c&s^xSEXKH{FCk2FP;+j%x4YLBKd)*N#fA=64{BVG zba6LRlHBw@4;^W^N9$MQr5Z3kgl`#W(Z!EijJfuYDb?-Rk-<=(n;rLAht1hq28Wor zM~<1pbw32m#XN_AxkJF*AzNJBRzY|U0dt3dxwdzIMXJalVD1nwcLY}!F>}ABkU3=zVZzRnM3zF|$U7Dh2D4&lS!)3*g{>N1Vhk-{nptmdztMEG zOgR&=HrCAuy6YpXE-O-&R)4V6UYiL|$T=xk!WZ1aP*D7RWM^ztjX zkvthaBiq_)c_ukIv)yPC>Sjz53_wcO+;ji;d!YcZ$!-EfzsW7T@FDT2K@b1|R28b~ zy5x*kX-owBmsP^e$gZ02X$B^Rzpya`Gi$U+LTG#H9J@)Vr)+b#nft2rUZ1X*6T9(I;)$84Uh@Q1NCd z(rTLI+607_tyaQI8;)r@zu2v-#w*q1fiKjGcPZ|GfQC0;q(_)sH~&Ktu0)z<9Q@BC zQZNze?H7F6Dgl*Ky(?ALj*=MeS3G+`X1o$|*d*wB3V#dzdU-sLUn)t;s4U6TBa$U~ zRfZxwG%V0>U#zfu!fnqrF(HC?Ow-bYf7j-wxvAB(d<9SRVcIl4jYL`Xw1ZpVFAAj~ zu;LE6qzElU*m6LdShpMIaH67Bc2AnW%}ml&qh3pPz;DYiH%y1n-5HW*f1kgQ6}q)6uz zbZH+j0@iO)&ecNN@QYB*xT9%&!DaZkehn{-TETcWpPTH$QA>vCP z<4W)fn$Abs2q@ZgiIyy-ACO0f!T$@J0{+>o3S?)I&-%C4p z@m)?c!*^T=ev_!>%i@K$<$<|K(SX(#=3c8?n@(0Gw@1XO+S=rtlG<-0lADNG4N2wSr*oc;Ro0`m9^bm&I(@jzE@m}Nf?Wd zXVr*F+&<$jY0M@09suS}8Q2P|aW1dK^2t8YtVo$0e*90kzcc&oP)y>(%h$)JZ(a{G z*IwQ?=D!x@x1ORqUXfd>Q7;2n0k4wc6?vV@N|@)nUZc*St+12nnSXT;Oo1D-`HG4E zK-c%OGk!~APHq_~1iMj&B?MbY(x8ekGYR;25zh+2vqW0C;-|VJp{HGv(dpLK95hy6 zP{8KYf9l7eTX((+|qoQ=33Th$>Giz{;t%R%kNL$ z%f6echH8Gu%IGj+#q7|u{t)Ih<9SkY5l;KmGqJWkEp{WGriQSGUy~D7%<2lCd2#}x zkOD6Rc4%o6QgH5dsjNiu&w1KD0^l$GCqQG3i^=Lo^k-Pr_iEj4g#mg4*8g41Z$I;Y zBv{##X|x*oziALIIT~JdT9q@Fmr0~=(oH~c^L!>}*V^iedpvynh6$0xOp>4jx_Rr8 zq@Ve-gnG(C0wlsiBUZiVT`wHs{sJNHEd*lS;D_CWJ$$}^hdmE8DLZ=?baP_rwy#J==8p}A`5rf| zWnf=qTK}nDbtLDp+n=~^R~=#38TU-DUSC~=?iWqUzNyAKr6s$i;R>s%Z>JVUPUBcG zDXjoD3(Px?8QA1@lNbuQH3^2VQn6}AldqB)i$27+Kv@sBQq258ah>6fI zXLQGQSeE{q2}*#2r{G1E>QLl*qE`w`Sj9W7-@k$B-pJqG*6MDi1h1Z_Z5KS)?aD?s z%>~-~_mif*t+Z_aJxD8MyJg}Xef#1?kLXGSa0@0t$X3ppS+7(uFjRC7wY>?^0cK^d zhhw+7+B?h54$Z|5i+}I+1g{il0XQya_kiQFbM%&7W47!Tsb$CbEcb!RvNJ4}fY^r> zaaRKIRKnB!g0NGzg_yEJ=0_Mh%IfJc_ko1+S@2IjAL_}@uukp+;bh0SCaa;Dtdd6- zmP5As2H7D>$%fb@TSFw-1`bK^Q5KfK){it2klyzBGuFc3304Fpn8OY9XoM@%_pIV< z+2&owyv5G@8;jFu8Acw-1}#X*)%m&8@NKVwOu`m_|NVk~DR*ipUDtT;MhmX}`p;Ge zH=cWE=h35o4<7w(CL?@aA90L6;^hWwRZlk0D}6A5`p74SK1v_o^(O6O3X22-APbtx zVV7QM-7iK{wfZD2OO_Qq;PU7qMi()rS>fjauZhujL7TF^m;gaq&g z!qbl>P_^!ORXZ>$NS~}{OfG*H zZ}V^G55kR0%niSEu$SC2i>&skX_>$ns3ck(@zJszkxG^bO2#r1e}@%@`8 zYO%mI+}UYIs6s80^b6i@j-0SC1uKc#r6+eV4O;+*uoA70nzIA=;$jhPOGlAdNIq## zkpOv0ZnF5}W&`PuESdLuy))MLh5>wwjvu^jx^E#EuyWuzAbhP@*@p-E`WpAk7+z{^KAI^=}`ND=!D;Nta9IFz%85fOxY>ik;+!=evPCE z3f8q37wpeu~V%$J4V>dU#| z1UFCVoo)O*00fsP6$3!Y0K#$ebDgoy$ev8WPBd8bdu6@19OmkgjFYKDCEqJe$W zz#PPStg8%6m-o43r4qf9l;$7(wFAvYRUs;`1kI(=Cu~o5F&iUz)u4V?JuUY#AB0?_ zj7ml_`cbJ*q5()#NfQ>Q(ZiG;513$yv|ZCK(*Ao#LMDRWN?6F8q@2dh?QOlD`rd>V zO2^WC=Agc5jTQuV_X*!DIwTgFl+{H4mjts0Cb7rHAoYbs%x+k!cFi#3za?o(hg?h# zSw46_(pN6Ou*son@$g5zLl2$baU1LLli4#$Z`J_>t3-DMuf@L)?A}x_8kje2Yax48xt_05B54owsxMZ-Q*({Rb?rzEQ~l2_S8BjC#< ztJ0F@j91F+tKaBo?3nz<1UJ)`F>1rf8rqR{sptqhxUEg{h-Ydd=P&4}=_!ENdx$9*5hI-Mhm%FE*v9WGym08LU>tyc- zXfLUlvc4G3U4{x@&0~Z$Rq|Ftgu^JRR-va_Jz8>ITB`e`q`F5ss`aU;c11(=IVq_2 z+;_jyW(%jC>fqgPhjY$PH%%ZFFq7+0Ooh`+Z7W1Km|9|8da4lG@AmZT&@8_c*&jL4 z4uGwt2EhLgwZk!Bv4BewSb%IxADI_)M;DYlD0xuwe9@9;iMKFdD!+QM6VQB=6f-79 zRZ{xX=0ndo>vo&ptLQfn39kUbrL49ay)h-xbU*4(PlwMS6%~#VUux;!cm8 z0chn#E0`x+_A8y}-Ms*auXR~1C;MOmv=;hE5;#tEU&Vrd>VUNLfTha5<{QmujucU` zIod(p;9SEyAXF0e2@(-OUGsgP8PjT?5-SEY57?HQ{<{P9;r$4W{d?TMzXu?P96!}6 zS?BKoX`~%LI)0EPEvtovsU3uE;{X^kTdYa_Ogj_p)>ItJrPV39CVQ&bf1j#z8{d|l!-EfM17&DLuk(BWtB2f zx7>BG^qE8{l{ya;25^-GLVGMfW)t(stWv9@!|+uF1ITEn}Yr zXckj?N1i^@)}-p}c&HcGaDJ-%^Vi|>w5g`aUk(C?kVwKS2&yqjKjjRv#sDsPd2QRh z;l80UL+@MpNnU>Y!n;;{aL0mC8Mr_$p=y(eaO+FAOJ8vGX4KLN>dvhF>e6#@+mo)1bUvLpwM0~Ek8O|GNy$K{MAf~0i9Qb{seMh4;= zj65!$Y*YKQjRxp`wrWi^Fz;IDfIEiPm;$##<=M${Mn$ZTr!Hk{smp5BlNnVDkr9@c z;!dp=-OP}@rqRs)Ra1C&^_db`Wf>Lo>uL40ISW?Ma{IKz0HdU1lpfV$HwKC>ON(1i zX}>&m5($LJ(-r1raq!(+@*a8(uW;k8wK{!fVYftUt*tG1t9-phwK#c=c7nHhWAwY7 zU~T)vyV^BDM>`DDy;+p9KBG4l5>qBXFFx3g z{0#aJ8kMv8mugbq3EGBbM4Mm}pl6SaZVL#S#9m@pjkm6=`eR3AtEz9O_vySEJib`b zwArj`jB@h-{J-D)0n3+Aq8SyXJd8vP|1+4Qm53^3a(G9xbklbn9UUEg_wuFw|8MpG zA3b}a|NrRei|<|>{o(10?_Pd)^zHNK-#-1r(X*#VFJJtD9BpTa{!+=3ia#73(Smbv zL!I?xNw2Rx?dZWA)&KuM%AacQm!P*p?E$MK69yR*oMH1dG0?EmTy*~J=4klc%i+^Q z_K9Xi%DU;h^u)(ACo+OMNTSN^6b(apa6dZ7i8bq%VKqk(mdxnuFjmW?J$&KBc=ozx39iA8a{nF z)R;kbIKz3TTXpqBd}E@p$l}mCC*T`(GOHd<1+R)%q`Q(q={G&6C7S|;uKw=<>6mi( zMbFP%`d?OtuurLoKXv?go|qt&BCP~Xm&Tx_)r<>Z)@r?9*tTVoPpg!Q#fQHknzP{5 z9N=DwahqVO+8UUdyLqZxie@aU(;<1m^5cuMpP!Ffe_l|U+T$_tG*YRrT*OH})i}Q? z6X2zRK^dO@PJPhc!PkH4z8`5U)|Lw4*XPt|jBXV-K%2~rDB}x8T1TkWE|(fUnC3>) zSk%jOaEG+y-{6lHpvCiPp8Qs~Ev;uFr6rRkXlf$2OqIaXxX^M&?}%XPoutYe?P=&k zxA(p2Z?{``?qpxnv0iIU9g5r1jRWk46+VyJAP}NsX$y5YVEq+rZ0hCf(N%p>sK1o{ zC=DN(>-(tL1b}@*e=2weZL&Nrc#>;(l?nWo)g((w2`VU)K$x}I>W#i)Nzw9Rzw4YIooQ zu6TQ@+;^mKi1*ob2B%f^qj}S;deF(J8WxeDjyoV%)k`+D`Tc6K0N+=7N0?f{U?(DgG z5@)b{=>6ciYDCjs&TrP$7nQ&Z+gkPjQpjRvl2o-|AlV&(zH7=&DLnD;2WFVwPJ_V%-<$y>TGnv zNHWcVp=om0{B~AJ^5h$J%N84VS3)-i2{-?;F?UIBL)Ei_=Sq$qst=>2iJ7{Aox1*w z{@3KmV>;oY{QZ`S{K;R}-k@+81$`k4vQqCiHOF&R)OoU!{`{Qqh+LxwtLhWh-u_%H z^v2W7h_yrL+Gs2Pv~B+S*nZ#J+uH?03BKk0PlsCPJZzC-9NLCH!0a48QJwr}-OG)e zuUj(h|Ed1N0RHgAKM!GfMKFeKVpKPeCTM)vpoY?kL~ucsx!TefK&~r|P_nr&-n2 zUH_irH%3h%q}9~!)5X8Py%%)WN((4R3v{gfAEzf2Yzv+Haj#))r<-{>KVCOOX9;}C zDhr=W3l3IgZ=C-O3HSCm`E482boNVR`SEj(#|Ne{rw_`HwS&JR3grZwj9mQTnZMnm zk*BMwstRG>bF0%Qms!t5e85XqHGu5BkQ$Ca@wO1G;v5rV(|r4a^6^K)?ZX#cgO&m?#$X|Y*3G;os$Bpl)SL#UJelatP?0G}QehG1gIjoa^`gyHmvTCvSo5th z9iJ?pfUaBr61}Q9t-y5cPL)G;x|OCzMbkweSwTrfC*fNzVeU6}WsVR3*ibe0J#H6(76d->I_*fwk6r0kF)zlfDckH`7#irA68lmA;-_3t zaw#@h{II!QHu-%q;QcY{_xoZX>`>5-khTygaahUBiznp6!b9dblw+kViqm?f^UuvfuUP;R?S@9wX~+uAS*gqt|^3LSj^`8TNxXp z6T;s|!0%g|TCK0uUVO+_eyFpr)3QBcG;Za}F}}y>`R9vTjp3`vFiAmsntkea5k5zU zij2Y84+aqQeO>2Ob{&g;*fYs&7aQ;FWetF zDt#fB%E;Pv-A3jG9hG;Hq!J(>Js*{W^>}JkWjaS6eVj_)*LwS(cF}mt#SM(Y_3L3t zAA26S`3}GixKrw~%shvi`(x^4vw}-jJsHWhZ(0c|4`fLyw1vu&>E*(Bzt}4ZeeKyR zTCGzSWXAowIyyYD&Axs7=!M{lMfY@nXSlYlnNEKTpvat?TgO^u6}=Y!a-iQcdmW{DmUFOy~(B+RWxBAb#%3 zn__=dlG8+wW|AvXMI=2O_eXWOFhnz;86 zztayA%q%>~&2|v$L;~GxA!Ry}=3dgvM+fOgXEwgnh(BSE*S6sg{N*K#1UE8nv&{VM zW@mEfZ*Jpj8Jd}BZF_v-)^S4!ZDhU(z4j28-qAS55re}Oqs7%CHPO#~=ZgCD@Id_Y zNTbs-0M*5b!79s;q-mk6tn24DZ$p%_yW|DzwNk;lgSXGRpDU~}*F2Tfa?Y@doOArp zu~kLDxJ!MaFX$cAnl%D`Bv^<9jODz@NoOm#ia_7Hgx1EOp+2o?B?O*-#DF)bALj>Q0{ZvD|a

-W6A3Ly)ZlB|8^dC710EPO7Bi0LTZbCf%e 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

dI%F9X#ulW(4r{*xMp zM-NZ?@H`F+`#0$jBgrg_tQEU3 z+UOuN?-?AM+#E_`Xu8sbReX&+u&};|4ISplDsC`3*1a6arPq`J%B7%rl;oV5zwU3y zj3Q$%Wwvr@y2mu0PROQ1`fGCnt6Gs;Tnx?<`A<~ktFOiN@9sn4hK`XTO*iptVs$TH z-|aLGi(=j@ROwVqvZsD5<@M@|s}uUF&rv5J|I2FKbtG90@*+~*7e>~YVmCxI_oRCZ zSKkfZSCD?^9+8g@@C_Pc$=^0A>y+4 z)6gA`GJHFGdkHa8U4|KwF14(%c|I5nsA5KIDU$k_li1MKHvNNx7CKn0e-d1V1xb}M zB~_I&dKpNzxEsi5CrMYRdiQX4^J=`9CO9CT?6|Qy^2E~84t2U@VRP}7Mw<@tmO@Kk zr|rP3_)kJ5_N20@hLLt9UmCHHF07BfAEun+UIN3JwXNk|41Yu_(}GXEf@&j^S1OGcg$f3EKpL1qxt2=FEvy z{1_{cvQ<7&e@XVYy%^&WF-PvWuiMN*O;D|WE`PrkRx%4X)DEqs&_Udf% z6ph_!X0VSuVY_V_3F5}N85xncCU*PTaxCh*;drk-yBBPbno)+!rghPh<~E%y!)^Uc zjlT9?q|@3ugUQY44R^UYvHkO9qFVZXaN_#q$%>UO4IH^FlCGmEVK<&GJ;Ljq0#KJ> z-l_#A>KsoPfx&KfHq_+^@sr(!wEJxShETBxpi^-@o^P_nz}}W}N>6c9B6L0U6Qvw3 zv)sq{d(?&?LmR!b`DGNoSNDeMyjx}Xm4PTa$=FDW+T$gUS ztv5(>D`vd_DhTb#TvZDM<1Elyh{>>}+|k>6C@x@-;zxUm(+st2t>U4=Vx0#dJmE0E#JnyUjw_Juxu z2R(!Y;;N_O11V;7jxX*btvd40uoSLcVs29dhJoNP26!B4cbdnLh~IHI=MtZAIOoh~ zJXaMqfzlrNdAA@f_zpL6CM0KFos%3WVx94_gh2n{MFi0WIAYe?MxrYtg0M64_u}}2 zM!E}#Wg%Vkq4UL+Y;vU1X`K2ifqDDb-dNC#d8vDN1lvowc4-erdK_OKK88~>m0Q-F zKIi3T?wqj9I;xDjCf4?A%Fm4x8{035$x%`(hYFK6az(rV^0 zND0ajO`jB}aTu?LNi{VnY?PU#Br~PU$jrR(V3a{A;WUL(GlrHLIz&`dXiY=i$cYk} z^ML&u`@xS)wAkP^^uE?C|2ibuE$(N?k?N*0H*(CkM^@(5M(X6o`0B)GfoO?k>%ove z52RQAe~+3rp9i*~hQ1*6b@9JE+8UeFSV};6B7DHkKJO|62k(ved$&u)6z6|*Pa(hq z9B?ddax4h<|)q?I6d*>h7L_tD0v?Av>S&NW@i z;%BE~AA%--*j^GT{)NdK2fjqMQd!p_s=|;3YjpQ3xZ(ck7w@`1rMq$&8c{P^F=KVX zByVy&9rMCc$_;C%AC9M;hLP(!9)_RrFs?Nw!nPSu7Of^lu9YDumvIbkp+r{^aBM;+E+wg(jLcjafjbJKsw#ytNi zJC2!anFlB>D1Yd*T2Nc2%e~nC;4J#emy#)hOV~nOpEyc}muZ;x(O$DiNRfB<+e#?}P}eCIW=j zezN>wK~2)_ohFezF^r`RUsY;p@ZC0D@fgM$Dg0eoz&+X{n?18%&}BNXVxHI&C@t(c zk788jkc~IZ%&z#lP~)}9T?*Vi#bF*>6SlpZ5I<8qXc4T^cfqG{a|;HAY&!8ceTrzu zp~8Fd-*7zExp(j~FPp9m9JH66#jFcYxDHxfwUwsxsYm#WtmHY3Uan?evOVw~KG{NA zG+rgk_Q)unmcJbfyu@<=U9@A`zd=L&Zd3^Y}hh3o(lJ?oZr+R z!Ze&ST-|$_|4-{c4e>XQo5X$5MYFDe*C~x7usvzxXouCg(8}9`Y@e9(6FDojPA>q! h>5M6-s{!UPz_Mk_mM#15`8NOn|Nm5zLO}ph1pux3L$&|_ literal 0 HcmV?d00001 diff --git a/assets/rancher-monitoring/rancher-monitoring-105.1.3+up61.3.2.tgz b/assets/rancher-monitoring/rancher-monitoring-105.1.3+up61.3.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..32576c63614345823b316d2bde9a8e58d8e71cec GIT binary patch literal 487891 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

O7lzIm}WaY#s2| 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'XtXm~AIHq}}RQFj!Xa(}1XBwvhNlyzeM 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

R%0r@A|S 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%0Afx5^4!&QF!p!v!` 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

V+NWL+XB=TZs?#Ih4bMiu1Y1= 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 Bnij*kx^ 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 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/namespace: cattle-logging-system + catalog.cattle.io/permits-os: linux,windows + catalog.cattle.io/provides-gvr: logging.banzaicloud.io.clusterflow/v1beta1 + catalog.cattle.io/rancher-version: '>= 2.10.0-0 < 2.11.0-0' + catalog.cattle.io/release-name: rancher-logging + catalog.cattle.io/type: cluster-tool + catalog.cattle.io/ui-component: logging + catalog.cattle.io/upstream-version: 4.10.0 +apiVersion: v2 +appVersion: 4.10.0 +description: Logging operator for Kubernetes based on Fluentd and Fluentbit. +home: https://kube-logging.github.io +icon: file://assets/logos/rancher-logging.svg +keywords: +- logging +- fluentd +- fluentbit +kubeVersion: '>=1.28.0-0' +name: rancher-logging +sources: +- https://github.com/kube-logging/logging-operator +- https://github.com/kube-logging/helm-charts/tree/main/charts/logging-operator +type: application +version: 105.2.1+up4.10.0 diff --git a/charts/rancher-logging/105.2.1+up4.10.0/README.md b/charts/rancher-logging/105.2.1+up4.10.0/README.md new file mode 100644 index 0000000000..0c9eb18015 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/README.md @@ -0,0 +1,135 @@ +# logging-operator + +![type: application](https://img.shields.io/badge/type-application-informational?style=flat-square) ![kube version: >=1.22.0-0](https://img.shields.io/badge/kube%20version->=1.22.0--0-informational?style=flat-square) [![artifact hub](https://img.shields.io/badge/artifact%20hub-logging--operator-informational?style=flat-square)](https://artifacthub.io/packages/helm/kube-logging/logging-operator) + +Logging operator for Kubernetes based on Fluentd and Fluentbit. + +**Homepage:** + +## TL;DR; + +```bash +helm install --generate-name --wait oci://ghcr.io/kube-logging/helm-charts/logging-operator +``` + +or to install with a specific version: + +```bash +helm install --generate-name --wait oci://ghcr.io/kube-logging/helm-charts/logging-operator --version $VERSION +``` + +## Introduction + +This chart bootstraps a [Logging Operator](https://github.com/kube-logging/logging-operator) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Kubernetes 1.19+ + +## Installing CRDs + +Use `createCustomResource=false` with Helm v3 to avoid trying to create CRDs from the `crds` folder and from templates at the same time. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| replicaCount | int | `1` | | +| image.repository | string | `"ghcr.io/kube-logging/logging-operator"` | Name of the image repository to pull the container image from. | +| image.tag | string | `""` | Image tag override for the default value (chart appVersion). | +| image.pullPolicy | string | `"IfNotPresent"` | [Image pull policy](https://kubernetes.io/docs/concepts/containers/images/#updating-images) for updating already existing images on a node. | +| env | list | `[]` | | +| volumes | list | `[]` | | +| volumeMounts | list | `[]` | | +| extraArgs[0] | string | `"-enable-leader-election=true"` | | +| imagePullSecrets | list | `[]` | | +| nameOverride | string | `""` | A name in place of the chart name for `app:` labels. | +| fullnameOverride | string | `""` | A name to substitute for the full names of resources. | +| namespaceOverride | string | `""` | A namespace override for the app. | +| annotations | object | `{}` | Define annotations for logging-operator pods. | +| createCustomResource | bool | `false` | Deploy CRDs used by Logging Operator. | +| http.port | int | `8080` | HTTP listen port number. | +| http.service | object | `{"annotations":{},"clusterIP":"None","labels":{},"type":"ClusterIP"}` | Service definition for query http service. | +| rbac.enabled | bool | `true` | Create rbac service account and roles. | +| monitoring.serviceMonitor.enabled | bool | `false` | Create a Prometheus Operator ServiceMonitor object. | +| monitoring.serviceMonitor.additionalLabels | object | `{}` | | +| monitoring.serviceMonitor.metricRelabelings | list | `[]` | | +| monitoring.serviceMonitor.relabelings | list | `[]` | | +| podSecurityContext | object | `{}` | Pod SecurityContext for Logging operator. [More info](https://kubernetes.io/docs/concepts/policy/security-context/) # SecurityContext holds pod-level security attributes and common container settings. # This defaults to non root user with uid 1000 and gid 2000. *v1.PodSecurityContext false # ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ | +| securityContext | object | `{}` | Container SecurityContext for Logging operator. [More info](https://kubernetes.io/docs/concepts/policy/security-context/) | +| priorityClassName | object | `{}` | Operator priorityClassName. | +| serviceAccount.annotations | object | `{}` | Define annotations for logging-operator ServiceAccount. | +| resources | object | `{}` | CPU/Memory resource requests/limits | +| nodeSelector | object | `{}` | | +| tolerations | list | `[]` | Node Tolerations | +| affinity | object | `{}` | Node Affinity | +| podLabels | object | `{}` | Define which Nodes the Pods are scheduled on. | +| logging | object | `{"allowClusterResourcesFromAllNamespaces":false,"clusterDomain":"cluster.local.","clusterFlows":[],"clusterOutputs":[],"controlNamespace":"","defaultFlow":{},"enableRecreateWorkloadOnImmutableFieldChange":false,"enabled":false,"errorOutputRef":"","eventTailer":{},"flowConfigCheckDisabled":false,"flowConfigOverride":"","fluentbit":{},"fluentbitDisabled":false,"fluentd":{},"fluentdDisabled":false,"globalFilters":[],"hostTailer":{},"loggingRef":"","nodeAgents":{},"skipInvalidResources":false,"syslogNG":{},"watchNamespaceSelector":{},"watchNamespaces":[]}` | Logging resources configuration. | +| logging.enabled | bool | `false` | Logging resources are disabled by default | +| logging.loggingRef | string | `""` | Reference to the logging system. Each of the loggingRefs can manage a fluentbit daemonset and a fluentd statefulset. | +| logging.flowConfigCheckDisabled | bool | `false` | Disable configuration check before applying new fluentd configuration. | +| logging.skipInvalidResources | bool | `false` | Whether to skip invalid Flow and ClusterFlow resources | +| logging.flowConfigOverride | string | `""` | Override generated config. This is a raw configuration string for troubleshooting purposes. | +| logging.fluentbitDisabled | bool | `false` | Flag to disable fluentbit completely | +| logging.fluentbit | object | `{}` | Fluent-bit configurations https://kube-logging.github.io/docs/configuration/crds/v1beta1/fluentbit_types/ | +| logging.fluentdDisabled | bool | `false` | Flag to disable fluentd completely | +| logging.fluentd | object | `{}` | Fluentd configurations https://kube-logging.github.io/docs/configuration/crds/v1beta1/fluentd_types/ | +| logging.syslogNG | object | `{}` | Syslog-NG statefulset configuration | +| logging.defaultFlow | object | `{}` | Default flow for unmatched logs. This Flow configuration collects all logs that didn’t match any other Flow. | +| logging.errorOutputRef | string | `""` | GlobalOutput name to flush ERROR events to | +| logging.globalFilters | list | `[]` | Global filters to apply on logs before any match or filter mechanism. | +| logging.watchNamespaces | list | `[]` | Limit namespaces to watch Flow and Output custom resources. | +| logging.watchNamespaceSelector | object | `{}` | Limit namespaces to watch Flow and Output custom resources. | +| logging.clusterDomain | string | `"cluster.local."` | Cluster domain name to be used when templating URLs to services | +| logging.controlNamespace | string | `""` | Namespace for cluster wide configuration resources like ClusterFlow and ClusterOutput. This should be a protected namespace from regular users. Resources like fluentbit and fluentd will run in this namespace as well. | +| logging.allowClusterResourcesFromAllNamespaces | bool | `false` | Allow configuration of cluster resources from any namespace. Mutually exclusive with ControlNamespace restriction of Cluster resources | +| logging.nodeAgents | object | `{}` | NodeAgent Configuration | +| logging.configCheck | object | `{}` | configCheck provides possibility for timeout-based configuration checks https://kube-logging.dev/docs/whats-new/#timeout-based-configuration-checks | +| logging.enableRecreateWorkloadOnImmutableFieldChange | bool | `false` | EnableRecreateWorkloadOnImmutableFieldChange enables the operator to recreate the fluentbit daemonset and the fluentd statefulset (and possibly other resource in the future) in case there is a change in an immutable field that otherwise couldn’t be managed with a simple update. | +| logging.enableDockerParserCompatibilityForCRI | bool | `false` | EnableDockerParserCompatibilityForCRI enables Docker log format compatibility for CRI workloads. | +| logging.clusterFlows | list | `[]` | ClusterFlows to deploy | +| logging.clusterOutputs | list | `[]` | ClusterOutputs to deploy | +| logging.eventTailer.enabled | bool | `false` | | +| logging.eventTailer.name | string | `"event-tailer"` | | +| logging.eventTailer.image.repository | string | `nil` | repository of eventTailer image | +| logging.eventTailer.image.tag | string | `nil` | tag of eventTailer image | +| logging.eventTailer.image.pullPolicy | string | `nil` | pullPolicy of eventTailer image | +| logging.eventTailer.image.imagePullSecrets | list | `[]` | imagePullSecrets of eventTailer image | +| logging.eventTailer.pvc.enabled | bool | `true` | enable pvc for | +| logging.eventTailer.pvc.accessModes | list | `["ReadWriteOnce"]` | storage class for event tailer pvc | +| logging.eventTailer.pvc.volumeMode | string | `"Filesystem"` | storage class for event tailer pvc | +| logging.eventTailer.pvc.storage | string | `"1Gi"` | storage for event tailer pvc | +| logging.eventTailer.pvc.storageClassName | string | `nil` | storage class for event tailer pvc | +| logging.eventTailer.workloadMetaOverrides | string | `nil` | workloadMetaOverrides | +| logging.eventTailer.workloadOverrides | string | `nil` | workloadOverrides | +| logging.eventTailer.containerOverrides | string | `nil` | containerOverrides | +| logging.hostTailer.enabled | bool | `false` | HostTailer | +| logging.hostTailer.name | string | `"hosttailer"` | name of HostTailer | +| logging.hostTailer.image.repository | string | `nil` | repository of eventTailer image | +| logging.hostTailer.image.tag | string | `nil` | tag of eventTailer image | +| logging.hostTailer.image.pullPolicy | string | `nil` | pullPolicy of eventTailer image | +| logging.hostTailer.image.imagePullSecrets | list | `[]` | imagePullSecrets of eventTailer image | +| logging.hostTailer.workloadMetaOverrides | string | `nil` | workloadMetaOverrides of HostTailer | +| logging.hostTailer.workloadOverrides | string | `nil` | workloadOverrides of HostTailer | +| logging.hostTailer.fileTailers | list | `[]` | configure fileTailers of HostTailer example: - name: sample-file path: /var/log/sample-file disabled: false buffer_max_size: buffer_chunk_size: skip_long_lines: read_from_head: false containerOverrides: image: | +| logging.hostTailer.systemdTailers | list | `[]` | configure systemdTailers of HostTailer example: - name: system-sample disabled: false systemdFilter: kubelet.service maxEntries: 20 containerOverrides: image: | +| testReceiver.enabled | bool | `false` | | +| testReceiver.image | string | `"fluent/fluent-bit"` | | +| testReceiver.pullPolicy | string | `"IfNotPresent"` | | +| testReceiver.port | int | `8080` | | +| testReceiver.args[0] | string | `"-i"` | | +| testReceiver.args[1] | string | `"http"` | | +| testReceiver.args[2] | string | `"-p"` | | +| testReceiver.args[3] | string | `"port=8080"` | | +| testReceiver.args[4] | string | `"-o"` | | +| testReceiver.args[5] | string | `"stdout"` | | +| testReceiver.resources.limits.cpu | string | `"100m"` | | +| testReceiver.resources.limits.memory | string | `"50Mi"` | | +| testReceiver.resources.requests.cpu | string | `"20m"` | | +| testReceiver.resources.requests.memory | string | `"25Mi"` | | +| extraManifests | list | `[]` | Extra manifests to deploy as an array | + +## Installing Fluentd and Fluent-bit via logging + +The chart does **not** install `logging` resource to deploy Fluentd (or Syslog-ng) and Fluent-bit on the cluster by default, but +it can be enabled by setting the `logging.enabled` value to true. diff --git a/charts/rancher-logging/105.2.1+up4.10.0/app-readme.md b/charts/rancher-logging/105.2.1+up4.10.0/app-readme.md new file mode 100644 index 0000000000..994c597ee5 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/app-readme.md @@ -0,0 +1,45 @@ +# Rancher Logging + +This chart is based off of the upstream [Banzai Logging Operator](https://banzaicloud.com/docs/one-eye/logging-operator/) chart. The chart deploys a logging operator and CRDs, which allows users to configure complex logging pipelines with a few simple custom resources. There are two levels of logging, which allow you to collect all logs in a cluster or from a single namespace. + +For more information on how to use the feature, refer to our [docs](https://rancher.com/docs/rancher/v2.x/en/logging/v2.7/). + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. + +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Namespace-level logging + +To collect logs from a single namespace, users create flows and these flows are connected to outputs or cluster outputs. + +## Cluster-level logging + +To collect logs from an entire cluster, users create cluster flows and cluster outputs. + +## CRDs + +- [Cluster Flow](https://banzaicloud.com/docs/one-eye/logging-operator/crds/v1beta1/clusterflow_types/) - A cluster flow is a CRD (`ClusterFlow`) that defines what logs to collect from the entire cluster. The cluster flow must be deployed in the same namespace as the logging operator. +- [Cluster Output](https://banzaicloud.com/docs/one-eye/logging-operator/crds/v1beta1/clusteroutput_types/) - A cluster output is a CRD (`ClusterOutput`) that defines how to connect to logging providers so they can start collecting logs. The cluster output must be deployed in the same namespace as the logging operator. The convenience of using a cluster output is that either a cluster flow or flow can send logs to those providers without needing to define specific outputs in each namespace for each flow. +- [Flow](https://banzaicloud.com/docs/one-eye/logging-operator/crds/v1beta1/flow_types/) - A flow is a CRD (`Flow`) that defines what logs to collect from the namespace that it is deployed in. +- [Output](https://banzaicloud.com/docs/one-eye/logging-operator/crds/v1beta1/output_types/) - An output is a CRD (`Output`) that defines how to connect to logging providers so logs can be sent to the provider. + +For more information on how to configure the Helm chart, refer to the Helm README. + +## Systemd Configuration +Some Kubernetes distributions log to journald. In order to collect these logs the `systemdLogPath` needs to be defined. While the `/run/log/journal` directory is used by default, some Linux distributions do not default to this path. For example Ubuntu defaults to `/var/log/journal`. To determine your `systemdLogPath` run `cat /etc/systemd/journald.conf | grep -E ^\#?Storage | cut -d"=" -f2` on one of your nodes. If `persistent` is returned your `systemdLogPath` should be `/var/log/journal`. If `volatile` is returned `systemdLogPath` should be `/run/log/journal`. If `auto` is returned check if `/var/log/journal` exists, and if it does then use `/var/log/journal`, otherwise use `/run/log/journal`. + +If any value not described here is returned, Rancher Logging will not be able to collect control plane logs. To address this issue set `Storage=volatile` in journald.conf, reboot your machine, and set `systemdLogPath` to `/run/log/journal`. diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/NOTES.txt b/charts/rancher-logging/105.2.1+up4.10.0/templates/NOTES.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/_generic_fluentbitagent.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/_generic_fluentbitagent.yaml new file mode 100644 index 0000000000..44f2303db3 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/_generic_fluentbitagent.yaml @@ -0,0 +1,85 @@ +{{- define "logging-operator.fluentbitagent.tpl" -}} +apiVersion: logging.banzaicloud.io/v1beta1 +kind: FluentbitAgent +metadata: + namespace: {{ .Release.Namespace }} + labels: +{{ include "logging-operator.labels" . | indent 4 }} +spec: + image: + repository: {{ template "logging-operator.fluentbitImageRepository" . }} + tag: {{ template "logging-operator.fluentbitImageTag" . }} + {{- if not .Values.disablePvc }} + {{- with .Values.fluentbit.bufferStorage }} + bufferStorage: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.fluentbit.bufferStorageVolume }} + bufferStorageVolume: {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} + {{- if or .Values.global.cattle.psp.enabled .Values.global.seLinux.enabled }} + security: + {{- end }} + {{- if .Values.global.cattle.psp.enabled }} + podSecurityPolicyCreate: true + roleBasedAccessControlCreate: true + {{- end }} + {{- if .Values.global.seLinux.enabled }} + securityContext: + seLinuxOptions: + type: rke_logreader_t + {{- end }} + {{- if or .Values.fluentbit.inputTail.Buffer_Chunk_Size .Values.fluentbit.inputTail.Buffer_Max_Size .Values.fluentbit.inputTail.Mem_Buf_Limit .Values.fluentbit.inputTail.Multiline_Flush .Values.fluentbit.inputTail.Skip_Long_Lines }} + inputTail: + {{- if .Values.fluentbit.inputTail.Buffer_Chunk_Size }} + Buffer_Chunk_Size: {{ .Values.fluentbit.inputTail.Buffer_Chunk_Size | toString }} + {{- end }} + {{- if .Values.fluentbit.inputTail.Buffer_Max_Size }} + Buffer_Max_Size: {{ .Values.fluentbit.inputTail.Buffer_Max_Size | toString }} + {{- end }} + {{- if .Values.fluentbit.inputTail.Mem_Buf_Limit }} + Mem_Buf_Limit: {{ .Values.fluentbit.inputTail.Mem_Buf_Limit | toString }} + {{- end }} + {{- if .Values.fluentbit.inputTail.Multiline_Flush }} + Multiline_Flush: {{ .Values.fluentbit.inputTail.Multiline_Flush | toString | quote }} + {{- end }} + {{- if .Values.fluentbit.inputTail.Skip_Long_Lines }} + Skip_Long_Lines: {{ .Values.fluentbit.inputTail.Skip_Long_Lines | toString | quote }} + {{- end }} + {{- end }} + {{- with (concat (.Values.tolerations) (.Values.fluentbit.tolerations)) }} + tolerations: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.fluentbit.resources }} + resources: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.fluentbit.metrics }} + metrics: {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} + +{{- define "logging-operator.util.merge.fluentbitagent" -}} +{{/* Top context to expose fields like `.Release` and `.Values` */}} +{{- $top := first . -}} + +{{/* tpl is the template specific to the fluentbit implementation */}} +{{- $tpl := fromYaml (include (index . 1) $top) | default (dict ) -}} + +{{/* Generic is the shared rancher fluentbit setttings from `_generic_fluentbitagent.yaml` */}} +{{- $generic := fromYaml (include (index . 2) $top) | default (dict ) -}} + +{{/* values are from the values.yaml */}} +{{- $values := $top.Values.fluentbitAgentOverlay | default (dict ) -}} + +####### {{$generic}} + +{{/* the sources are merge right to left meaning tpl is the highest prcedence and values is the lowest */}} +{{- toYaml (merge $tpl $values $generic) -}} +{{- end -}} + +{{- define "logging-operator.fluentbitagent" -}} +{{- include "logging-operator.util.merge.fluentbitagent" (append . "logging-operator.fluentbitagent.tpl") -}} +{{- end -}} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/_generic_logging.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/_generic_logging.yaml new file mode 100644 index 0000000000..ee39ef9682 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/_generic_logging.yaml @@ -0,0 +1,75 @@ +{{- define "logging-operator.logging.tpl" -}} +apiVersion: logging.banzaicloud.io/v1beta1 +kind: Logging +metadata: + namespace: {{ .Release.Namespace }} + labels: +{{ include "logging-operator.labels" . | indent 4 }} +spec: + controlNamespace: {{ .Release.Namespace }} + fluentd: + {{- with .Values.fluentd.logLevel }} + logLevel: {{ . }} + {{- end }} + image: + repository: {{ template "system_default_registry" . }}{{ .Values.images.fluentd.repository }} + tag: {{ .Values.images.fluentd.tag }} + configReloaderImage: + repository: {{ template "system_default_registry" . }}{{ .Values.images.config_reloader.repository }} + tag: {{ .Values.images.config_reloader.tag }} + {{- with .Values.fluentd.bufferStorageVolume }} + bufferStorageVolume: {{- toYaml . | nindent 6 }} + {{- end }} + disablePvc: {{ .Values.disablePvc }} + {{- if .Values.fluentd.replicas }} + scaling: + replicas: {{ .Values.fluentd.replicas }} + {{- end }} + security: + podSecurityContext: + {{- if .Values.global.cattle.psp.enabled }} + podSecurityPolicyCreate: true + roleBasedAccessControlCreate: true + {{- end }} + {{- with .Values.fluentd.env }} + envVars: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with (default .Values.tolerations .Values.fluentd.tolerations) }} + tolerations: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with (default .Values.nodeSelector .Values.fluentd.nodeSelector) }} + nodeSelector: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.fluentd.resources }} + resources: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.fluentd.livenessProbe }} + livenessProbe: {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.fluentd.metrics }} + metrics: {{- toYaml . | nindent 6 }} + {{- end }} +{{- end -}} + +{{- define "logging-operator.util.merge.logging" -}} +{{/* Top context to expose fields like `.Release` and `.Values` */}} +{{- $top := first . -}} + +{{/* tpl is the template specific to the logging implementation */}} +{{- $tpl := fromYaml (include (index . 1) $top) | default (dict ) -}} + +{{/* Generic is the shared rancher logging setttings from `_generic_logging.yaml` */}} +{{- $generic := fromYaml (include (index . 2) $top) | default (dict ) -}} + +{{/* values are from the values.yaml */}} +{{- $values := $top.Values.loggingOverlay | default (dict ) -}} + +####### {{$generic}} + +{{/* the sources are merge right to left meaning tpl is the highest prcedence and values is the lowest */}} +{{- toYaml (merge $tpl $values $generic) -}} +{{- end -}} + +{{- define "logging-operator.logging" -}} +{{- include "logging-operator.util.merge.logging" (append . "logging-operator.logging.tpl") -}} +{{- end -}} \ No newline at end of file diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/_helpers.tpl b/charts/rancher-logging/105.2.1+up4.10.0/templates/_helpers.tpl new file mode 100644 index 0000000000..98ffa95685 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/_helpers.tpl @@ -0,0 +1,231 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "logging-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 "logging-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 -}} + +{{/* +Expand the name of the release. +*/}} +{{- define "logging-operator.releasename" -}} +{{- default .Release.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Provides the namespace the chart will be installed in using the builtin .Release.Namespace, +or, if provided, a manually overwritten namespace value. +*/}} +{{- define "logging-operator.namespace" -}} +{{- if .Values.namespaceOverride -}} +{{ .Values.namespaceOverride -}} +{{- else -}} +{{ .Release.Namespace }} +{{- end -}} +{{- end -}} + + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "logging-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "logging-operator.labels" -}} +app.kubernetes.io/name: {{ include "logging-operator.name" . }} +helm.sh/chart: {{ include "logging-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 -}} + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- else -}} +{{- "" -}} +{{- end -}} +{{- end -}} + +{{- define "windowsEnabled" }} +{{- if not (kindIs "invalid" .Values.global.cattle.windows) }} +{{- if not (kindIs "invalid" .Values.global.cattle.windows.enabled) }} +{{- if .Values.global.cattle.windows.enabled }} +true +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +{{- define "windowsPathPrefix" -}} +{{- trimSuffix "/" (default "c:\\" .Values.global.cattle.rkeWindowsPathPrefix | replace "\\" "/" | replace "//" "/" | replace "c:" "C:") -}} +{{- end -}} + +{{- define "windowsKubernetesFilter" -}} +{{- printf "kubernetes.%s" ((include "windowsPathPrefix" .) | replace ":" "" | replace "/" ".") -}} +{{- end -}} + +{{- define "windowsInputTailMount" -}} +{{- (include "windowsPathPrefix" .) | replace "C:" "" -}} +{{- end -}} + +{{/* +Set the controlplane selector based on kubernetes distribution +*/}} +{{- define "controlplaneSelector" -}} +{{- $master := or .Values.additionalLoggingSources.rke2.enabled .Values.additionalLoggingSources.k3s.enabled -}} +{{- $defaultSelector := $master | ternary (dict "node-role.kubernetes.io/master" "true") (dict "node-role.kubernetes.io/controlplane" "true") -}} +{{ default $defaultSelector .Values.additionalLoggingSources.kubeAudit.nodeSelector | toYaml }} +{{- end -}} + +{{/* +Set kube-audit file path prefix based on distribution +*/}} +{{- define "kubeAuditPathPrefix" -}} +{{- if .Values.additionalLoggingSources.rke.enabled -}} +{{ default "/var/log/kube-audit" .Values.additionalLoggingSources.kubeAudit.pathPrefix }} +{{- else if .Values.additionalLoggingSources.rke2.enabled -}} +{{ default "/var/lib/rancher/rke2/server/logs" .Values.additionalLoggingSources.kubeAudit.pathPrefix }} +{{- else -}} +{{ required "Directory PathPrefix of the kube-audit location is required" .Values.additionalLoggingSources.kubeAudit.pathPrefix }} +{{- end -}} +{{- end -}} + +{{/* +Set kube-audit file name based on distribution +*/}} +{{- define "kubeAuditFilename" -}} +{{- if .Values.additionalLoggingSources.rke.enabled -}} +{{ default "audit-log.json" .Values.additionalLoggingSources.kubeAudit.auditFilename }} +{{- else if .Values.additionalLoggingSources.rke2.enabled -}} +{{ default "audit.log" .Values.additionalLoggingSources.kubeAudit.auditFilename }} +{{- else -}} +{{ required "Filename of the kube-audit log is required" .Values.additionalLoggingSources.kubeAudit.auditFilename }} +{{- end -}} +{{- end -}} + +{{/* +A shared list of custom parsers for the vairous fluentbit pods rancher creates +*/}} +{{- define "logging-operator.parsers" -}} +[PARSER] + Name klog + Format regex + Regex ^(?[IWEF])(?\d{4} \d{2}:\d{2}:\d{2}).\d{6} +?(?\d+) (?.+):(?\d+)] (?.+) + Time_Key timestamp + Time_Format %m%d %T + +[PARSER] + Name rancher + Format regex + Regex ^time="(?.+)" level=(?.+) msg="(?.+)"$ + Time_Key timestamp + Time_Format %FT%H:%M:%S +[PARSER] + Name etcd + Format json + Time_Key timestamp + Time_Format %FT%H:%M:%S.%L +{{- end -}} + +{{/* +Set kubernetes log options if they are configured +*/}} +{{- define "requireFilterKubernetes" -}} +{{- if or .Values.fluentbit.filterKubernetes.Merge_Log .Values.fluentbit.filterKubernetes.Merge_Log_Key .Values.fluentbit.filterKubernetes.Merge_Trim .Values.fluentbit.filterKubernetes.Merge_Parser -}} +true +{{- end -}} +{{- end -}} + +{{/*Fluent Bit Image Repository */}} +{{- define "logging-operator.fluentbitImageRepository" -}} +{{- if .Values.debug -}} +{{ template "system_default_registry" . }}{{ .Values.images.fluentbit_debug.repository }} +{{- else -}} +{{ template "system_default_registry" . }}{{ .Values.images.fluentbit.repository }} +{{- end -}} +{{- end -}} + +{{/*Fluent Bit Image Tag */}} +{{- define "logging-operator.fluentbitImageTag" -}} +{{- if .Values.debug -}} +{{ .Values.images.fluentbit_debug.tag }} +{{- else -}} +{{ .Values.images.fluentbit.tag }} +{{- end -}} +{{- end -}} + +{{/*Fluent Bit Image */}} +{{- define "logging-operator.fluentbitImage" -}} +{{ template "logging-operator.fluentbitImageRepository" . }}:{{ template "logging-operator.fluentbitImageTag" . }} +{{- end -}} + +{{/* +Formats the cluster domain as a suffix, e.g.: +.Values.clusterDomain == "", returns "" +.Values.clusterDomain == "cluster.local.", returns ".cluster.local." +*/}} +{{- define "logging-operator.clusterDomainAsSuffix" -}} +{{- if .Values.clusterDomain -}} +{{- printf ".%s" .Values.clusterDomain -}} +{{- end -}} +{{- end -}} + +{{/* Implements logic to add the loggingRef field to custom loggings based on the cluster type */}} +{{- define "logging-operator.individualLoggingRef" -}} +{{- with .loggingRef -}} +loggingRef: {{ . }} +{{- end -}} +{{- end -}} + +{{/* Implements logic to add fluentd spec fields to custom loggings based on the cluster type */}} +{{- define "logging-operator.individualFluentd" -}} +{{- if .fluentd -}} +{{- if .fluentd.scaling -}} +scaling: + replicas: {{ .fluentd.scaling.replicas }} +{{- end }} +{{- with .fluentd.resources }} +resources: {{ toYaml . | nindent 2 }} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* Implements logic to add fluentbit loggingRef field to custom loggings based on the cluster type */}} +{{- define "logging-operator.individualFluentbitLoggingRef" -}} +{{- with .loggingRef -}} +loggingRef: {{ . }} +{{- end -}} +{{- end -}} + +{{/* Implements logic to add fluentbit spec fields to custom fluentBitAgents based on the cluster type */}} +{{- define "logging-operator.individualFluentbit" -}} +{{- with .resources }} +resources: {{ toYaml . | nindent 2 }} +{{- end -}} +{{- end -}} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/clusterrole.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/clusterrole.yaml new file mode 100644 index 0000000000..1fb9bce779 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/clusterrole.yaml @@ -0,0 +1,242 @@ +{{- if .Values.rbac.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "logging-operator.fullname" . }} +rules: +- apiGroups: + - "" + resources: + - configmaps + - persistentvolumeclaims + - pods + - secrets + - serviceaccounts + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - endpoints + - namespaces + - nodes + - nodes/proxy + verbs: + - get + - list + - watch +- apiGroups: + - "" + - events.k8s.io + resources: + - events + verbs: + - create + - get + - list + - watch +- apiGroups: + - apps + resources: + - daemonsets + - replicasets + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - apps + - extensions + resources: + - daemonsets + - deployments + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - '*' +- apiGroups: + - events.k8s.io + resources: + - events + verbs: + - get + - list + - watch +- apiGroups: + - extensions + - networking.k8s.io + resources: + - ingresses + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - extensions + - policy + resources: + - podsecuritypolicies + verbs: + - create + - delete + - get + - list + - patch + - update + - use + - watch +- apiGroups: + - logging-extensions.banzaicloud.io + resources: + - eventtailers + - hosttailers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - logging-extensions.banzaicloud.io + resources: + - eventtailers/status + - hosttailers/status + verbs: + - get + - patch + - update +- apiGroups: + - logging.banzaicloud.io + resources: + - clusterflows + - clusteroutputs + - flows + - fluentbitagents + - fluentdconfigs + - loggingroutes + - loggings + - nodeagents + - outputs + - syslogngclusterflows + - syslogngclusteroutputs + - syslogngconfigs + - syslogngflows + - syslogngoutputs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - logging.banzaicloud.io + resources: + - clusterflows/status + - clusteroutputs/status + - flows/status + - fluentbitagents/status + - fluentdconfigs/status + - loggingroutes/status + - loggings/status + - nodeagents/status + - outputs/status + - syslogngclusterflows/status + - syslogngclusteroutputs/status + - syslogngconfigs/status + - syslogngflows/status + - syslogngoutputs/status + verbs: + - get + - patch + - update +- apiGroups: + - logging.banzaicloud.io + resources: + - loggings/finalizers + verbs: + - update +- apiGroups: + - monitoring.coreos.com + resources: + - prometheusrules + - servicemonitors + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + - clusterroles + - rolebindings + - roles + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/clusterrolebinding.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/clusterrolebinding.yaml new file mode 100644 index 0000000000..89d17d094f --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/clusterrolebinding.yaml @@ -0,0 +1,18 @@ +{{- if .Values.rbac.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "logging-operator.fullname" . }} + labels: +{{ include "logging-operator.labels" . | indent 4 }} +subjects: + - kind: ServiceAccount + name: {{ template "logging-operator.fullname" . }} + namespace: {{ include "logging-operator.namespace" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "logging-operator.fullname" . }} + + {{- end }} \ No newline at end of file diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/crds.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/crds.yaml new file mode 100644 index 0000000000..f573652d04 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/crds.yaml @@ -0,0 +1,6 @@ +{{- if .Values.createCustomResource -}} +{{- range $path, $bytes := .Files.Glob "crds/*.yaml" }} +{{ $.Files.Get $path }} +--- +{{- end }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/deployment.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/deployment.yaml new file mode 100644 index 0000000000..0cdf494e97 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/deployment.yaml @@ -0,0 +1,79 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "logging-operator.fullname" . }} + namespace: {{ include "logging-operator.namespace" . }} + labels: +{{ include "logging-operator.labels" . | indent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "logging-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "logging-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + {{- with .Values.podLabels }} + {{ toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ template "system_default_registry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + args: + {{- range .Values.extraArgs }} + - {{ . }} + {{- end }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + ports: + - name: http + containerPort: {{ .Values.http.port }} + {{- with .Values.env }} + env: {{ toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.securityContext }} + securityContext: {{ toYaml .Values.securityContext | nindent 12 }} + {{- end }} + {{- with .Values.volumeMounts }} + volumeMounts: {{ toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: {{ toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.podSecurityContext }} + securityContext: {{ toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.rbac.serviceAccountName }} + serviceAccountName: {{ .Values.rbac.serviceAccountName }} + {{- else if .Values.rbac.enabled }} + serviceAccountName: {{ include "logging-operator.fullname" . }} + {{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/extra-manifests.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/extra-manifests.yaml new file mode 100644 index 0000000000..567f7bf329 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/extra-manifests.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraManifests }} +--- +{{ tpl (toYaml .) $ }} +{{ end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/clusterflows.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/clusterflows.yaml new file mode 100644 index 0000000000..3a1a46bee5 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/clusterflows.yaml @@ -0,0 +1,14 @@ +{{ if .Values.logging.enabled -}} +{{- range $clusterflow := .Values.logging.clusterFlows }} +--- +apiVersion: logging.banzaicloud.io/v1beta1 +kind: ClusterFlow +metadata: + name: {{ $clusterflow.name }} + namespace: {{ $.Values.logging.controlNamespace | default $.Release.Namespace }} + labels: +{{ include "logging-operator.labels" $ | indent 4 }} +spec: +{{ toYaml $clusterflow.spec | indent 2 }} +{{- end -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/clusteroutputs.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/clusteroutputs.yaml new file mode 100644 index 0000000000..60d9f30ae7 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/clusteroutputs.yaml @@ -0,0 +1,14 @@ +{{ if .Values.logging.enabled -}} +{{- range $clusteroutput := .Values.logging.clusterOutputs }} +--- +apiVersion: logging.banzaicloud.io/v1beta1 +kind: ClusterOutput +metadata: + name: {{ $clusteroutput.name }} + namespace: {{ $.Values.logging.controlNamespace | default $.Release.Namespace }} + labels: +{{ include "logging-operator.labels" $ | indent 4 }} +spec: +{{ toYaml $clusteroutput.spec | indent 2 }} +{{- end -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/eventtailer.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/eventtailer.yaml new file mode 100644 index 0000000000..830cf9b15d --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/eventtailer.yaml @@ -0,0 +1,41 @@ +{{- with $.Values.logging.eventTailer }} +{{- if and $.Values.logging.enabled .enabled }} +apiVersion: logging-extensions.banzaicloud.io/v1alpha1 +kind: EventTailer +metadata: + name: {{ .name }} +spec: + controlNamespace: {{ $.Values.logging.controlNamespace | default $.Release.Namespace }} + {{- with .image }} + image: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .pvc }} + {{- if .enabled }} + positionVolume: + pvc: + spec: + accessModes: {{ .accessModes }} + resources: + requests: + storage: {{ .storage }} + volumeMode: {{ .volumeMode }} + {{- with .storageClassName }} + storageClassName: {{ . }} + {{- end }} + {{- end }}{{/* end if enabled */}} + {{- end }}{{/* end with pvc */}} + {{- with .workloadMetaOverrides }} + workloadMetaOverrides: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .workloadOverrides }} + workloadOverrides: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .containerOverrides }} + containerOverrides: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }}{{/* end if enabled */}} +{{- end }}{{/* end with event-tailer */}} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/fluentbit.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/fluentbit.yaml new file mode 100644 index 0000000000..ad9bdcb319 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/fluentbit.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.logging.enabled (not .Values.logging.fluentbitDisabled) -}} +{{- $fluentbitSpec := .Values.logging.fluentbit }} +{{- if .Values.logging.loggingRef }} + {{- $fluentbitSpec := set .Values.logging.fluentbit "loggingRef" (default .Values.logging.loggingRef .Values.logging.fluentbit.loggingRef) -}} +{{- end }} + +apiVersion: logging.banzaicloud.io/v1beta1 +kind: FluentbitAgent +metadata: + name: {{ include "logging-operator.releasename" . }} + labels: {{ include "logging-operator.labels" . | nindent 4 }} +{{- if $fluentbitSpec }} +spec: {{- toYaml $fluentbitSpec | nindent 2 }} +{{- else }} +spec: {} +{{- end }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/hosttailer.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/hosttailer.yaml new file mode 100644 index 0000000000..a14d7c10b7 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/hosttailer.yaml @@ -0,0 +1,31 @@ +{{- with .Values.logging.hostTailer }} +{{- if and $.Values.logging.enabled .enabled }} +--- +apiVersion: logging-extensions.banzaicloud.io/v1alpha1 +kind: HostTailer +metadata: + name: {{ .name }} +spec: + {{- with .fileTailers }} + fileTailers: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .systemdTailers }} + systemdTailers: + {{- toYaml . | nindent 4 }} + {{- end }} + enableRecreateWorkloadOnImmutableFieldChange: {{ $.Values.logging.enableRecreateWorkloadOnImmutableFieldChange }} + {{- with .workloadMetaOverrides }} + workloadMetaOverrides: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .workloadOverrides }} + workloadOverrides: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .image }} + image: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/logging.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/logging.yaml new file mode 100644 index 0000000000..9bb9a959be --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/logging/logging.yaml @@ -0,0 +1,63 @@ +{{ if .Values.logging.enabled -}} +apiVersion: logging.banzaicloud.io/v1beta1 +kind: Logging +metadata: + name: {{ include "logging-operator.releasename" . }} + labels: +{{ include "logging-operator.labels" . | indent 4 }} +spec: + {{- with .Values.logging.loggingRef }} + loggingRef: {{ . }} + {{- end }} + {{- with .Values.logging.flowConfigCheckDisabled }} + flowConfigCheckDisabled: {{ . }} + {{- end }} + {{- with .Values.logging.skipInvalidResources }} + skipInvalidResources: {{ . }} + {{- end }} + {{- with .Values.logging.flowConfigOverride }} + flowConfigOverride: {{ . }} + {{- end }} + {{- if (not .Values.logging.fluentdDisabled) }} + {{- if .Values.logging.fluentd }} + fluentd: {{- toYaml .Values.logging.fluentd | nindent 4 }} + {{- else }} + fluentd: {} + {{- end }} + {{- end }} + {{- with .Values.logging.syslogNG }} + syslogNG: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.logging.defaultFlow }} + defaultFlow: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.logging.errorOutputRef }} + errorOutputRef: {{ . }} + {{- end }} + {{- with .Values.logging.globalFilters }} + globalFilters: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.logging.watchNamespaces }} + watchNamespaces: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.logging.watchNamespaceSelector }} + watchNamespaceSelector: {{- toYaml . | nindent 4 }} + {{- end }} + clusterDomain: {{ .Values.logging.clusterDomain }} + controlNamespace: {{ .Values.logging.controlNamespace | default .Release.Namespace }} + {{- with .Values.logging.allowClusterResourcesFromAllNamespaces }} + allowClusterResourcesFromAllNamespaces: {{ . }} + {{- end }} + {{- with .Values.logging.nodeAgents }} + nodeAgents: {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.logging.enableRecreateWorkloadOnImmutableFieldChange }} + enableRecreateWorkloadOnImmutableFieldChange: {{ . }} + {{- end }} + {{- with .Values.logging.enableDockerParserCompatibilityForCRI }} + enableDockerParserCompatibilityForCRI: {{ . }} + {{- end }} + {{- with .Values.logging.configCheck }} + configCheck: {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/aks/fluentbitagent.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/aks/fluentbitagent.yaml new file mode 100644 index 0000000000..8f06a2ed4e --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/aks/fluentbitagent.yaml @@ -0,0 +1,20 @@ +{{- define "logging-operator.fluentbitagent.aks" -}} +{{- $logPath := "/var/log/azure/kubelet-status.log" -}} +{{- $individualValues := .Values.additionalLoggingSources.aks.fluentbit -}} +metadata: + name: {{ .Release.Name }}-aks +spec: + disableKubernetesFilter: true + extraVolumeMounts: + - source: {{ $logPath }} + destination: {{ $logPath }} + readOnly: true + inputTail: + Tag: "aks" + Path: {{ $logPath }} +{{- include "logging-operator.individualFluentbitLoggingRef" $individualValues | nindent 2 }} +{{- include "logging-operator.individualFluentbit" $individualValues | nindent 2 }} +{{- end -}} +{{- if .Values.additionalLoggingSources.aks.enabled }} +{{- include "logging-operator.fluentbitagent" (list . "logging-operator.fluentbitagent.aks") -}} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/aks/logging.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/aks/logging.yaml new file mode 100644 index 0000000000..abed474351 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/aks/logging.yaml @@ -0,0 +1,12 @@ +{{- define "logging-operator.logging.aks" -}} +{{- $individualValues := .Values.additionalLoggingSources.aks -}} +metadata: + name: {{ .Release.Name }}-aks +spec: + {{- include "logging-operator.individualLoggingRef" $individualValues | nindent 2 }} + fluentd: + {{- include "logging-operator.individualFluentd" $individualValues | nindent 4 }} +{{- end -}} +{{- if .Values.additionalLoggingSources.aks.enabled }} +{{- include "logging-operator.logging" (list . "logging-operator.logging.aks") -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/eks/fluentbitagent.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/eks/fluentbitagent.yaml new file mode 100644 index 0000000000..cf0ca31336 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/eks/fluentbitagent.yaml @@ -0,0 +1,21 @@ +{{- define "logging-operator.fluentbitagent.eks" -}} +{{- $logPath := "/var/log/messages" -}} +{{- $individualValues := .Values.additionalLoggingSources.eks.fluentbit -}} +metadata: + name: {{ .Release.Name }}-eks +spec: + {{- include "logging-operator.individualFluentbitLoggingRef" $individualValues | nindent 2 }} + disableKubernetesFilter: true + extraVolumeMounts: + - source: {{ $logPath }} + destination: {{ $logPath }} + readOnly: true + inputTail: + Tag: "eks" + Path: {{ $logPath }} + Parser: "syslog" + {{- include "logging-operator.individualFluentbit" $individualValues | nindent 2 }} +{{- end -}} +{{- if .Values.additionalLoggingSources.eks.enabled }} +{{- include "logging-operator.fluentbitagent" (list . "logging-operator.fluentbitagent.eks") -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/eks/logging.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/eks/logging.yaml new file mode 100644 index 0000000000..830d8ec390 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/eks/logging.yaml @@ -0,0 +1,20 @@ +{{- define "logging-operator.logging.eks" -}} +{{- $individualValues := .Values.additionalLoggingSources.eks -}} +metadata: + name: {{ .Release.Name }}-eks +spec: + {{- include "logging-operator.individualLoggingRef" $individualValues | nindent 2 }} + fluentd: + {{- include "logging-operator.individualFluentd" $individualValues | nindent 4 }} + {{- if .Values.loggingServiceAccountAnnotations.eks -}} + serviceAccount: + metadata: + annotations: + {{- with .Values.loggingServiceAccountAnnotations.eks }} + {{ toYaml . | indent 8 }} + {{- end }} + {{- end }} +{{- end -}} +{{- if .Values.additionalLoggingSources.eks.enabled }} +{{- include "logging-operator.logging" (list . "logging-operator.logging.eks") -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/gke/fluentbitagent.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/gke/fluentbitagent.yaml new file mode 100644 index 0000000000..7541332404 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/gke/fluentbitagent.yaml @@ -0,0 +1,20 @@ +{{- define "logging-operator.fluentbitagent.gke" -}} +{{- $logPath := "/var/log/kube-proxy.log" -}} +{{- $individualValues := .Values.additionalLoggingSources.gke.fluentbit -}} +metadata: + name: {{ .Release.Name }}-gke +spec: + {{- include "logging-operator.individualFluentbitLoggingRef" $individualValues | nindent 2 }} + disableKubernetesFilter: true + extraVolumeMounts: + - source: {{ $logPath }} + destination: {{ $logPath }} + readOnly: true + inputTail: + Tag: "gke" + Path: {{ $logPath }} + {{- include "logging-operator.individualFluentbit" $individualValues | nindent 2 }} +{{- end -}} +{{- if .Values.additionalLoggingSources.gke.enabled }} +{{- include "logging-operator.fluentbitagent" (list . "logging-operator.fluentbitagent.gke") -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/gke/logging.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/gke/logging.yaml new file mode 100644 index 0000000000..80ed58e280 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/gke/logging.yaml @@ -0,0 +1,12 @@ +{{- define "logging-operator.logging.gke" -}} +{{- $individualValues := .Values.additionalLoggingSources.gke -}} +metadata: + name: {{ .Release.Name }}-gke +spec: + {{- include "logging-operator.individualLoggingRef" $individualValues | nindent 2 }} + fluentd: + {{- include "logging-operator.individualFluentd" $individualValues | nindent 4 }} +{{- end -}} +{{- if .Values.additionalLoggingSources.gke.enabled }} +{{- include "logging-operator.logging" (list . "logging-operator.logging.gke") -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/configmap.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/configmap.yaml new file mode 100644 index 0000000000..aa454c8adf --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/configmap.yaml @@ -0,0 +1,57 @@ +{{- if and .Values.additionalLoggingSources.k3s.enabled (eq .Values.additionalLoggingSources.k3s.container_engine "systemd") }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-k3s + labels: +{{ include "logging-operator.labels" . | indent 4 }} +data: + fluent-bit.conf: | + [SERVICE] + Flush 1 + Grace 5 + Daemon Off + Log_Level info + Coro_Stack_Size 24576 + Parsers_File parsers.conf + + [INPUT] + Name systemd + Tag k3s + Path {{ .Values.systemdLogPath }} + Systemd_Filter _SYSTEMD_UNIT=k3s.service + {{- if .Values.additionalLoggingSources.k3s.stripUnderscores }} + Strip_Underscores On + {{- end }} + Systemd_Filter _SYSTEMD_UNIT=k3s-agent.service + + [FILTER] + Name parser + Match * + Key_Name MESSAGE + Parser klog + Reserve_Data On + + [FILTER] + Name parser + Match * + Key_Name MESSAGE + Parser rancher + Reserve_Data On + + [FILTER] + Name parser + Match * + Key_Name MESSAGE + Parser etcd + Reserve_Data On + + [OUTPUT] + Name forward + Match * + Host {{ .Release.Name }}-root-fluentd.{{ .Release.Namespace }}.svc + Port 24240 + Retry_Limit False + parsers.conf: | +{{ include "logging-operator.parsers" . | indent 4 }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/daemonset.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/daemonset.yaml new file mode 100644 index 0000000000..4700873fe7 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/daemonset.yaml @@ -0,0 +1,112 @@ +{{- if and .Values.additionalLoggingSources.k3s.enabled (eq .Values.additionalLoggingSources.k3s.container_engine "systemd") }} +{{- $individualValues := .Values.additionalLoggingSources.k3s.fluentbit -}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: "{{ .Release.Name }}-k3s-journald-aggregator" + namespace: "{{ .Release.Namespace }}" +spec: + selector: + matchLabels: + name: {{ .Release.Name }}-k3s-journald-aggregator + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/loggings/k3s/configmap.yaml") . | sha256sum }} + name: "{{ .Release.Name }}-k3s-journald-aggregator" + namespace: "{{ .Release.Namespace }}" + labels: + name: {{ .Release.Name }}-k3s-journald-aggregator + spec: + containers: + - name: fluentbit + image: "{{ template "logging-operator.fluentbitImage" . }}" + {{- include "logging-operator.individualFluentbit" $individualValues | nindent 10 }} + {{- if .Values.global.seLinux.enabled }} + securityContext: + seLinuxOptions: + type: rke_logreader_t + {{- end }} + volumeMounts: + - mountPath: /fluent-bit/etc/ + name: config + - mountPath: {{ .Values.systemdLogPath | default "/var/log/journal" }} + name: journal + readOnly: true + - mountPath: /etc/machine-id + name: machine-id + readOnly: true + {{- with .Values.tolerations }} + tolerations: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: "{{ .Release.Name }}-k3s-journald-aggregator" + volumes: + - name: config + configMap: + name: "{{ .Release.Name }}-k3s" + - name: journal + hostPath: + path: {{ .Values.systemdLogPath | default "/var/log/journal" }} + - name: machine-id + hostPath: + path: /etc/machine-id +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "{{ .Release.Name }}-k3s-journald-aggregator" + namespace: "{{ .Release.Namespace }}" +{{- if .Values.global.cattle.psp.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: "{{ .Release.Name }}-k3s-journald-aggregator" +rules: + - apiGroups: + - policy + resourceNames: + - "{{ .Release.Name }}-k3s-journald-aggregator" + resources: + - podsecuritypolicies + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: "{{ .Release.Name }}-k3s-journald-aggregator" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: "{{ .Release.Name }}-k3s-journald-aggregator" +subjects: + - kind: ServiceAccount + name: "{{ .Release.Name }}-k3s-journald-aggregator" +--- +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: "{{ .Release.Name }}-k3s-journald-aggregator" + namespace: "{{ .Release.Namespace }}" +spec: + allowPrivilegeEscalation: false + fsGroup: + rule: RunAsAny + readOnlyRootFilesystem: true + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - configMap + - emptyDir + - secret + - hostPath +{{- end }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/fluentbitagent.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/fluentbitagent.yaml new file mode 100644 index 0000000000..9bde882ad0 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/fluentbitagent.yaml @@ -0,0 +1,21 @@ +{{- define "logging-operator.fluentbitagent.k3s-openrc" -}} +{{- $logPath := "/var/log/k3s.log" -}} +{{- $individualValues := .Values.additionalLoggingSources.k3s.fluentbit -}} +metadata: + name: {{ .Release.Name }}-k3s +spec: + {{- include "logging-operator.individualFluentbitLoggingRef" $individualValues | nindent 2 }} + disableKubernetesFilter: true + extraVolumeMounts: + - source: {{ $logPath }} + destination: {{ $logPath }} + readOnly: true + inputTail: + Tag: "k3s" + Path: {{ $logPath }} + Path_Key: filename + {{- include "logging-operator.individualFluentbit" $individualValues | nindent 2 }} +{{- end -}} +{{- if and .Values.additionalLoggingSources.k3s.enabled (eq .Values.additionalLoggingSources.k3s.container_engine "openrc")}} +{{- include "logging-operator.fluentbitagent" (list . "logging-operator.fluentbitagent.k3s-openrc") -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/logging-k3s-openrc.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/logging-k3s-openrc.yaml new file mode 100644 index 0000000000..d305dce3cf --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/k3s/logging-k3s-openrc.yaml @@ -0,0 +1,12 @@ +{{- define "logging-operator.logging.k3s-openrc" -}} +{{- $individualValues := .Values.additionalLoggingSources.k3s -}} +metadata: + name: {{ .Release.Name }}-k3s +spec: + {{- include "logging-operator.individualLoggingRef" $individualValues | nindent 2 }} + fluentd: + {{- include "logging-operator.individualFluentd" $individualValues | nindent 4 }} +{{- end -}} +{{- if and .Values.additionalLoggingSources.k3s.enabled (eq .Values.additionalLoggingSources.k3s.container_engine "openrc")}} +{{- include "logging-operator.logging" (list . "logging-operator.logging.k3s-openrc") -}} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/kube-audit/fluentbitagent.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/kube-audit/fluentbitagent.yaml new file mode 100644 index 0000000000..c0e17a71b5 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/kube-audit/fluentbitagent.yaml @@ -0,0 +1,24 @@ +{{- define "logging-operator.fluentbitagent.kube-audit" -}} +{{- $individualValues := .Values.additionalLoggingSources.kubeAudit.fluentbit -}} +metadata: + name: {{ .Release.Name }}-kube-audit +spec: + {{- include "logging-operator.individualFluentbitLoggingRef" $individualValues | nindent 2 }} + disableKubernetesFilter: true + extraVolumeMounts: + - source: {{ template "kubeAuditPathPrefix" . }} + destination: "/kube-audit-logs" + readOnly: true + inputTail: + Tag: {{ .Values.additionalLoggingSources.kubeAudit.fluentbit.logTag }} + Path: /kube-audit-logs/{{ template "kubeAuditFilename" . }} + Parser: json + {{- with (concat (.Values.tolerations) (.Values.fluentbit.tolerations) (.Values.additionalLoggingSources.kubeAudit.fluentbit.tolerations)) }} + tolerations: {{- toYaml . | nindent 6 }} + {{- end }} + nodeSelector: {{ include "controlplaneSelector" . | nindent 6 }} + {{- include "logging-operator.individualFluentbit" $individualValues | nindent 2 }} +{{- end -}} +{{- if .Values.additionalLoggingSources.kubeAudit.enabled }} +{{- include "logging-operator.fluentbitagent" (list . "logging-operator.fluentbitagent.kube-audit") -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/kube-audit/logging.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/kube-audit/logging.yaml new file mode 100644 index 0000000000..b2e5fc24c2 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/kube-audit/logging.yaml @@ -0,0 +1,15 @@ +{{- define "logging-operator.logging.kube-audit" -}} +{{- $individualValues := .Values.additionalLoggingSources.kubeAudit -}} +metadata: + name: {{ .Release.Name }}-kube-audit +spec: + {{- include "logging-operator.individualLoggingRef" $individualValues | nindent 2 }} + {{- if .Values.additionalLoggingSources.kubeAudit.loggingRef }} + loggingRef: {{ .Values.additionalLoggingSources.kubeAudit.loggingRef }} + {{- end }} + fluentd: + {{- include "logging-operator.individualFluentd" $individualValues | nindent 4 }} +{{- end -}} +{{- if .Values.additionalLoggingSources.kubeAudit.enabled }} +{{- include "logging-operator.logging" (list . "logging-operator.logging.kube-audit") -}} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke/configmap.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke/configmap.yaml new file mode 100644 index 0000000000..252572a4ef --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke/configmap.yaml @@ -0,0 +1,29 @@ +{{- if .Values.additionalLoggingSources.rke.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-rke + labels: +{{ include "logging-operator.labels" . | indent 4 }} +data: + fluent-bit.conf: | + [SERVICE] + Log_Level {{ .Values.additionalLoggingSources.rke.fluentbit.log_level }} + Parsers_File parsers.conf + + [INPUT] + Tag rke + Name tail + Path_Key filename + Parser docker + DB /tail-db/tail-containers-state.db + Mem_Buf_Limit {{ .Values.additionalLoggingSources.rke.fluentbit.mem_buffer_limit }} + Path /var/lib/rancher/rke/log/*.log + + [OUTPUT] + Name forward + Match * + Host {{ .Release.Name }}-root-fluentd.{{ .Release.Namespace }}.svc + Port 24240 + Retry_Limit False +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke/daemonset.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke/daemonset.yaml new file mode 100644 index 0000000000..b050e8d17e --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke/daemonset.yaml @@ -0,0 +1,124 @@ +{{- if .Values.additionalLoggingSources.rke.enabled }} +{{- $containers := printf "%s/containers/" (default "/var/lib/docker" .Values.global.dockerRootDirectory) }} +{{- $individualValues := .Values.additionalLoggingSources.rke.fluentbit -}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: "{{ .Release.Name }}-rke-aggregator" + namespace: "{{ .Release.Namespace }}" +spec: + selector: + matchLabels: + name: {{ .Release.Name }}-rke-aggregator + template: + metadata: + name: "{{ .Release.Name }}-rke-aggregator" + namespace: "{{ .Release.Namespace }}" + labels: + name: {{ .Release.Name }}-rke-aggregator + spec: + containers: + - name: fluentbit + image: "{{ template "logging-operator.fluentbitImage" . }}" + {{- include "logging-operator.individualFluentbit" $individualValues | nindent 10 }} + volumeMounts: + - mountPath: /var/lib/rancher/rke/log/ + name: indir + - mountPath: {{ $containers }} + name: containers + - mountPath: /tail-db + name: positiondb + - mountPath: /fluent-bit/etc/fluent-bit.conf + name: config + subPath: fluent-bit.conf + {{- if .Values.global.seLinux.enabled }} + securityContext: + seLinuxOptions: + type: rke_logreader_t + {{- end }} + volumes: + - name: indir + hostPath: + path: /var/lib/rancher/rke/log/ + type: DirectoryOrCreate + - name: containers + hostPath: + path: {{ $containers }} + type: DirectoryOrCreate + - name: positiondb + emptyDir: {} + - name: config + configMap: + name: "{{ .Release.Name }}-rke" + serviceAccountName: "{{ .Release.Name }}-rke-aggregator" + {{- $total_tolerations := concat (.Values.tolerations) (.Values.fluentbit.tolerations) }} + {{- with $total_tolerations }} + tolerations: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 8 }} + {{- end }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "{{ .Release.Name }}-rke-aggregator" + namespace: "{{ .Release.Namespace }}" +{{- if .Values.global.cattle.psp.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: "{{ .Release.Name }}-rke-aggregator" +rules: + - apiGroups: + - policy + resourceNames: + - "{{ .Release.Name }}-rke-aggregator" + resources: + - podsecuritypolicies + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: "{{ .Release.Name }}-rke-aggregator" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: "{{ .Release.Name }}-rke-aggregator" +subjects: + - kind: ServiceAccount + name: "{{ .Release.Name }}-rke-aggregator" +--- +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: "{{ .Release.Name }}-rke-aggregator" + namespace: "{{ .Release.Namespace }}" +spec: + allowPrivilegeEscalation: false + allowedHostPaths: + - pathPrefix: {{ $containers }} + readOnly: false + - pathPrefix: /var/lib/rancher/rke/log/ + readOnly: false + - pathPrefix: /var/lib/rancher/logging/ + readOnly: false + fsGroup: + rule: RunAsAny + readOnlyRootFilesystem: true + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - configMap + - emptyDir + - secret + - hostPath +{{- end }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke2/configmap.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke2/configmap.yaml new file mode 100644 index 0000000000..3ca20be226 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke2/configmap.yaml @@ -0,0 +1,69 @@ +{{- if .Values.additionalLoggingSources.rke2.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-rke2 + labels: +{{ include "logging-operator.labels" . | indent 4 }} +data: + fluent-bit.conf: | + [SERVICE] + Flush 1 + Grace 5 + Daemon Off + Log_Level info + Coro_Stack_Size 24576 + Parsers_File parsers.conf + + [INPUT] + Name systemd + Tag rke2 + Path {{ .Values.systemdLogPath }} + Systemd_Filter _SYSTEMD_UNIT=rke2-server.service + Systemd_Filter _SYSTEMD_UNIT=rke2-agent.service + {{- if .Values.additionalLoggingSources.rke2.stripUnderscores }} + Strip_Underscores On + {{- end }} + + [INPUT] + Name tail + Tag rke2 + Path /var/lib/rancher/rke2/agent/logs/kubelet.log + + [FILTER] + Name parser + Match * + Key_Name log + Parser klog + Reserve_Data On + + [FILTER] + Name parser + Match * + Key_Name MESSAGE + Parser klog + Reserve_Data On + + [FILTER] + Name parser + Match * + Key_Name MESSAGE + Parser rancher + Reserve_Data On + + [FILTER] + Name parser + Match * + Key_Name MESSAGE + Parser etcd + Reserve_Data On + + [OUTPUT] + Name forward + Match * + Host {{ .Release.Name }}-root-fluentd.{{ .Release.Namespace }}.svc + Port 24240 + Retry_Limit False + parsers.conf: | +{{ include "logging-operator.parsers" . | indent 4 }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke2/daemonset.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke2/daemonset.yaml new file mode 100644 index 0000000000..37f3b353a1 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/rke2/daemonset.yaml @@ -0,0 +1,118 @@ +{{- if .Values.additionalLoggingSources.rke2.enabled }} +{{- $individualValues := .Values.additionalLoggingSources.rke2.fluentbit -}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: "{{ .Release.Name }}-rke2-journald-aggregator" + namespace: "{{ .Release.Namespace }}" +spec: + selector: + matchLabels: + name: {{ .Release.Name }}-rke2-journald-aggregator + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/loggings/rke2/configmap.yaml") . | sha256sum }} + name: "{{ .Release.Name }}-rke2-journald-aggregator" + namespace: "{{ .Release.Namespace }}" + labels: + name: {{ .Release.Name }}-rke2-journald-aggregator + spec: + containers: + - name: fluentbit + image: "{{ template "logging-operator.fluentbitImage" . }}" + {{- include "logging-operator.individualFluentbit" $individualValues | nindent 10 }} + {{- if .Values.global.seLinux.enabled }} + securityContext: + seLinuxOptions: + type: rke_logreader_t + {{- end }} + volumeMounts: + - mountPath: /fluent-bit/etc/ + name: config + - mountPath: {{ .Values.systemdLogPath | default "/var/log/journal" }} + name: journal + readOnly: true + - mountPath: "/var/lib/rancher/rke2/agent/logs" + name: kubelet + readOnly: true + - mountPath: /etc/machine-id + name: machine-id + readOnly: true + {{- with .Values.tolerations }} + tolerations: {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: "{{ .Release.Name }}-rke2-journald-aggregator" + volumes: + - name: config + configMap: + name: "{{ .Release.Name }}-rke2" + - name: journal + hostPath: + path: {{ .Values.systemdLogPath | default "/var/log/journal" }} + - name: kubelet + hostPath: + path: "/var/lib/rancher/rke2/agent/logs" + - name: machine-id + hostPath: + path: /etc/machine-id +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "{{ .Release.Name }}-rke2-journald-aggregator" + namespace: "{{ .Release.Namespace }}" +{{- if .Values.global.cattle.psp.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: "{{ .Release.Name }}-rke2-journald-aggregator" +rules: + - apiGroups: + - policy + resourceNames: + - "{{ .Release.Name }}-rke2-journald-aggregator" + resources: + - podsecuritypolicies + verbs: + - use +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: "{{ .Release.Name }}-rke2-journald-aggregator" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: "{{ .Release.Name }}-rke2-journald-aggregator" +subjects: + - kind: ServiceAccount + name: "{{ .Release.Name }}-rke2-journald-aggregator" +--- +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: "{{ .Release.Name }}-rke2-journald-aggregator" + namespace: "{{ .Release.Namespace }}" +spec: + allowPrivilegeEscalation: false + fsGroup: + rule: RunAsAny + readOnlyRootFilesystem: true + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - configMap + - emptyDir + - secret + - hostPath +{{- end }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/root/fluentbitagent.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/root/fluentbitagent.yaml new file mode 100644 index 0000000000..2816b7f911 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/root/fluentbitagent.yaml @@ -0,0 +1,29 @@ +{{- define "logging-operator.fluentbitagent.root" -}} +{{- $containerLogPath := printf "%s/containers/" (default "/var/lib/docker" .Values.global.dockerRootDirectory) }} +metadata: + name: "{{ .Release.Name }}-root" +spec: + {{- if .Values.global.dockerRootDirectory }} + mountPath: {{ $containerLogPath }} + extraVolumeMounts: + - source: {{ $containerLogPath }} + destination: {{ $containerLogPath }} + readOnly: true + {{- end }} + {{- if (include "requireFilterKubernetes" .) }} + filterKubernetes: + {{- if .Values.fluentbit.filterKubernetes.Merge_Log }} + Merge_Log: "{{ .Values.fluentbit.filterKubernetes.Merge_Log }}" + {{- end }} + {{- if .Values.fluentbit.filterKubernetes.Merge_Log_Key }} + Merge_Log_Key: "{{ .Values.fluentbit.filterKubernetes.Merge_Log_Key }}" + {{- end }} + {{- if .Values.fluentbit.filterKubernetes.Merge_Log_Trim }} + Merge_Log_Trim: "{{ .Values.fluentbit.filterKubernetes.Merge_Log_Trim }}" + {{- end }} + {{- if .Values.fluentbit.filterKubernetes.Merge_Parser }} + Merge_Parser: "{{ .Values.fluentbit.filterKubernetes.Merge_Parser }}" + {{- end }} + {{- end }} +{{- end -}} +{{- include "logging-operator.fluentbitagent" (list . "logging-operator.fluentbitagent.root") -}} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/root/logging.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/root/logging.yaml new file mode 100644 index 0000000000..e225815e1c --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/loggings/root/logging.yaml @@ -0,0 +1,67 @@ +{{- define "logging-operator.logging.root" -}} +metadata: + name: "{{ .Release.Name }}-root" +spec: + {{- if (include "windowsEnabled" .) }} + nodeAgents: + - name: win-agent + profile: windows + nodeAgentFluentbit: + daemonSet: + spec: + template: + spec: + containers: + - image: {{ template "system_default_registry" . }}{{ .Values.images.nodeagent_fluentbit.repository }}:{{ .Values.images.nodeagent_fluentbit.tag }} + name: fluent-bit + tls: + enabled: {{ .Values.nodeAgents.tls.enabled | default false }} + {{- if .Values.additionalLoggingSources.rke.enabled }} + - name: win-agent-rke + profile: windows + nodeAgentFluentbit: + filterKubernetes: + Kube_Tag_Prefix: "{{ template "windowsKubernetesFilter" . }}.var.lib.rancher.rke.log." + inputTail: + Path: "{{ template "windowsPathPrefix" . }}/var/lib/rancher/rke/log" + {{- if .Values.fluentbit.inputTail.Buffer_Chunk_Size }} + Buffer_Chunk_Size: {{ .Values.fluentbit.inputTail.Buffer_Chunk_Size | toString }} + {{- end }} + {{- if .Values.fluentbit.inputTail.Buffer_Max_Size }} + Buffer_Max_Size: {{ .Values.fluentbit.inputTail.Buffer_Max_Size | toString }} + {{- end }} + {{- if .Values.fluentbit.inputTail.Mem_Buf_Limit }} + Mem_Buf_Limit: {{ .Values.fluentbit.inputTail.Mem_Buf_Limit | toString }} + {{- end }} + {{- if .Values.fluentbit.inputTail.Multiline_Flush }} + Multiline_Flush: {{ .Values.fluentbit.inputTail.Multiline_Flush | toString | quote }} + {{- end }} + {{- if .Values.fluentbit.inputTail.Skip_Long_Lines }} + Skip_Long_Lines: {{ .Values.fluentbit.inputTail.Skip_Long_Lines | toString | quote }} + {{- end }} + extraVolumeMounts: + - source: "{{ template "windowsInputTailMount" . }}/var/lib/rancher/rke/log" + destination: "{{ template "windowsInputTailMount" . }}/var/lib/rancher/rke/log" + readOnly: true + daemonSet: + spec: + template: + spec: + containers: + - image: "{{ template "system_default_registry" . }}{{ .Values.images.nodeagent_fluentbit.repository }}:{{ .Values.images.nodeagent_fluentbit.tag }}" + name: fluent-bit + tls: + enabled: {{ .Values.nodeAgents.tls.enabled | default false }} + {{- end }} + {{- end }} + fluentd: + {{- if .Values.loggingServiceAccountAnnotations.root }} + serviceAccount: + metadata: + annotations: + {{- with .Values.loggingServiceAccountAnnotations.root }} + {{ toYaml . | indent 8 }} + {{- end }} + {{- end -}} +{{- end -}} +{{- include "logging-operator.logging" (list . "logging-operator.logging.root") -}} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/service.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/service.yaml new file mode 100644 index 0000000000..0a829d32ea --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "logging-operator.fullname" . }} + namespace: {{ include "logging-operator.namespace" . }} + labels: +{{ include "logging-operator.labels" . | indent 4 }} +spec: + type: {{ .Values.http.service.type }} + {{- with .Values.http.service.clusterIP }} + clusterIP: {{ . }} + {{- end }} + ports: + - port: {{ .Values.http.port }} + targetPort: http + protocol: TCP + name: http + selector: + app.kubernetes.io/name: {{ include "logging-operator.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/service_monitor.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/service_monitor.yaml new file mode 100644 index 0000000000..fcd86b07a9 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/service_monitor.yaml @@ -0,0 +1,30 @@ +{{ if and (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1") .Values.monitoring.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "logging-operator.fullname" . }} + namespace: {{ include "logging-operator.namespace" . }} + labels: +{{ include "logging-operator.labels" . | indent 4 }} +{{- with .Values.monitoring.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} +{{- end }} +spec: + selector: + matchLabels: +{{ include "logging-operator.labels" . | indent 6 }} + endpoints: + - port: http + path: /metrics + {{- with .Values.monitoring.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.monitoring.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 4 }} + {{- end }} + namespaceSelector: + matchNames: + - {{ include "logging-operator.namespace" . }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/serviceaccount.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/serviceaccount.yaml new file mode 100644 index 0000000000..bb97cf1084 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- if .Values.rbac.enabled }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "logging-operator.fullname" . }} + namespace: {{ include "logging-operator.namespace" . }} + labels: +{{ include "logging-operator.labels" . | indent 4 }} +{{- with .Values.serviceAccount.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/test_receiver.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/test_receiver.yaml new file mode 100644 index 0000000000..af0b5f4dcc --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/test_receiver.yaml @@ -0,0 +1,53 @@ +{{ if .Values.testReceiver.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "logging-operator.releasename" . }}-test-receiver + namespace: {{ include "logging-operator.namespace" . }} +spec: + type: ClusterIP + ports: + - port: {{ .Values.testReceiver.port }} + targetPort: receiver + protocol: TCP + name: receiver + selector: + app.kubernetes.io/name: {{ include "logging-operator.releasename" . }}-test-receiver + app.kubernetes.io/instance: {{ .Release.Name }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "logging-operator.releasename" . }}-test-receiver + namespace: {{ include "logging-operator.namespace" . }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ include "logging-operator.releasename" . }}-test-receiver + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "logging-operator.releasename" . }}-test-receiver + app.kubernetes.io/instance: {{ .Release.Name }} + annotations: + fluentbit.io/exclude: "true" + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.testReceiver.image }}" + args: + {{- range .Values.testReceiver.args }} + - {{ . }} + {{- end }} + imagePullPolicy: {{ .Values.testReceiver.pullPolicy }} + resources: + {{- toYaml .Values.testReceiver.resources | nindent 12 }} + ports: + - name: receiver + containerPort: {{ .Values.testReceiver.port }} +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/userrole.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/userrole.yaml new file mode 100644 index 0000000000..82c3200b9c --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/userrole.yaml @@ -0,0 +1,39 @@ +{{- if .Values.rbac.enabled }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "logging-operator.fullname" . }}-edit + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: +- apiGroups: + - logging.banzaicloud.io + resources: + - flows + - outputs + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +- apiGroups: + - logging.banzaicloud.io + resources: + - syslogngflows + - syslogngoutputs + verbs: + - create + - delete + - deletecollection + - get + - list + - patch + - update + - watch +{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/userroles.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/userroles.yaml new file mode 100644 index 0000000000..f4136b09a4 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/userroles.yaml @@ -0,0 +1,35 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: "logging-admin" + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: + - apiGroups: + - "logging.banzaicloud.io" + resources: + - flows + - outputs + verbs: + - "*" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: "logging-view" + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-view: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" +rules: + - apiGroups: + - "logging.banzaicloud.io" + resources: + - flows + - outputs + - clusterflows + - clusteroutputs + verbs: + - get + - list + - watch diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-install-crd.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..5184c85c47 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-install-crd.yaml @@ -0,0 +1,29 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "logging-extensions.banzaicloud.io/v1alpha1/EventTailer" false -}} +# {{- set $found "logging-extensions.banzaicloud.io/v1alpha1/HostTailer" false -}} +# {{- set $found "logging.banzaicloud.io/v1alpha1/ClusterFlow" false -}} +# {{- set $found "logging.banzaicloud.io/v1alpha1/ClusterOutput" false -}} +# {{- set $found "logging.banzaicloud.io/v1alpha1/Flow" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/FluentbitAgent" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/FluentdConfig" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/LoggingRoute" false -}} +# {{- set $found "logging.banzaicloud.io/v1alpha1/Logging" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/NodeAgent" false -}} +# {{- set $found "logging.banzaicloud.io/v1alpha1/Output" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/SyslogNGClusterFlow" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/SyslogNGClusterOutput" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/SyslogNGConfig" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/SyslogNGFlow" false -}} +# {{- set $found "logging.banzaicloud.io/v1beta1/SyslogNGOutput" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install the corresponding CRD chart before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} \ No newline at end of file diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-install.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-install.yaml new file mode 100644 index 0000000000..bd624cc4b4 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-install.yaml @@ -0,0 +1,5 @@ +#{{- if .Values.global.dockerRootDirectory }} +#{{- if or (hasSuffix "/containers" .Values.global.dockerRootDirectory) (hasSuffix "/" .Values.global.dockerRootDirectory) }} +#{{- required "global.dockerRootDirectory must not end with suffix: '/' or '/containers'" "" -}} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-psp-install.yaml b/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-logging/105.2.1+up4.10.0/values-logging-example.yaml b/charts/rancher-logging/105.2.1+up4.10.0/values-logging-example.yaml new file mode 100644 index 0000000000..b7068af4a0 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/values-logging-example.yaml @@ -0,0 +1,24 @@ +nameOverride: example + +# given we use `nameOverride: example` if testReceiver is enabled we can send http metrics to http://example-test-receiver:8080 +testReceiver: + enabled: true + +logging: + enabled: true + clusterFlows: + - name: all + spec: + match: + - select: {} + globalOutputRefs: ["http"] + clusterOutputs: + - name: http + spec: + http: + endpoint: http://example-test-receiver:8080 + content_type: application/json + buffer: + type: memory + timekey: 1s + timekey_wait: 1s diff --git a/charts/rancher-logging/105.2.1+up4.10.0/values.yaml b/charts/rancher-logging/105.2.1+up4.10.0/values.yaml new file mode 100644 index 0000000000..c8edf6a2a7 --- /dev/null +++ b/charts/rancher-logging/105.2.1+up4.10.0/values.yaml @@ -0,0 +1,495 @@ +# Default values for logging-operator. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: rancher/mirrored-kube-logging-logging-operator + tag: 4.10.0 + pullPolicy: IfNotPresent + +env: [] +volumes: [] +volumeMounts: [] + +extraArgs: + - -enable-leader-election=true +imagePullSecrets: [] + +# -- A name in place of the chart name for `app:` labels. +nameOverride: "" + +# -- A name to substitute for the full names of resources. +fullnameOverride: "" + +# -- A namespace override for the app. +namespaceOverride: "" + +# -- Define annotations for logging-operator pods. +annotations: {} + +# -- Deploy CRDs used by Logging Operator. +createCustomResource: false + +http: + # -- HTTP listen port number. + port: 8080 + + # -- Service definition for query http service. + service: + type: ClusterIP + clusterIP: None + # Annotations to query http service + annotations: {} + # Labels to query http service + labels: {} + +rbac: + # -- Create rbac service account and roles. + enabled: true + + # specify service account manually + # serviceAccountName: custom + +monitoring: + serviceMonitor: + # -- Create a Prometheus Operator ServiceMonitor object. + enabled: false + + additionalLabels: {} + metricRelabelings: [] + relabelings: [] + +# -- Pod SecurityContext for Logging operator. [More info](https://kubernetes.io/docs/concepts/policy/security-context/) +## SecurityContext holds pod-level security attributes and common container settings. +## This defaults to non root user with uid 1000 and gid 2000. *v1.PodSecurityContext false +## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ +podSecurityContext: {} +# runAsNonRoot: true +# runAsUser: 1000 +# fsGroup: 2000 + +# -- Container SecurityContext for Logging operator. [More info](https://kubernetes.io/docs/concepts/policy/security-context/) +securityContext: {} +# allowPrivilegeEscalation: false +# readOnlyRootFilesystem: true + # capabilities: + # drop: ["ALL"] + +# -- Operator priorityClassName. +priorityClassName: {} + +serviceAccount: + # -- Define annotations for logging-operator ServiceAccount. + annotations: {} + +# -- CPU/Memory resource requests/limits +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +# -- Node Tolerations +tolerations: [] + +# -- Node Affinity +affinity: {} + +# -- Define which Nodes the Pods are scheduled on. +podLabels: {} + +# Logging resources configuration. +logging: + + # -- Logging resources are disabled by default + enabled: false + + # -- Reference to the logging system. Each of the loggingRefs can manage a 1bit daemonset and a fluentd statefulset. + loggingRef: "" + + # -- Disable configuration check before applying new fluentd configuration. + flowConfigCheckDisabled: false + + # -- Whether to skip invalid Flow and ClusterFlow resources + skipInvalidResources: false + + # -- Override generated config. This is a raw configuration string for troubleshooting purposes. + flowConfigOverride: "" + + # -- Flag to disable fluentbit completely + fluentbitDisabled: false + # -- Fluent-bit configurations https://kube-logging.github.io/docs/configuration/crds/v1beta1/fluentbit_types/ + fluentbit: {} + + # -- Flag to disable fluentd completely + fluentdDisabled: false + # -- Fluentd configurations https://kube-logging.github.io/docs/configuration/crds/v1beta1/fluentd_types/ + fluentd: {} + # 20Gi persistent storage is configured for fluentd by default. + # Here is an example, on how to override it: + # bufferStorageVolume: + # pvc: + # spec: + # accessModes: + # - ReadWriteOnce + # resources: + # requests: + # storage: 40Gi + + # -- Syslog-NG statefulset configuration + syslogNG: {} + + # -- Default flow for unmatched logs. This Flow configuration collects all logs that didn’t match any other Flow. + defaultFlow: {} + + # -- GlobalOutput name to flush ERROR events to + errorOutputRef: "" + + # -- Global filters to apply on logs before any match or filter mechanism. + globalFilters: [] + + # -- Limit namespaces to watch Flow and Output custom resources. + watchNamespaces: [] + + # -- Limit namespaces to watch Flow and Output custom resources. + watchNamespaceSelector: {} + + # -- Cluster domain name to be used when templating URLs to services + clusterDomain: "cluster.local." + + # -- Namespace for cluster wide configuration resources like ClusterFlow and ClusterOutput. This should be a protected namespace from regular users. Resources like fluentbit and fluentd will run in this namespace as well. + controlNamespace: "" + + # -- Allow configuration of cluster resources from any namespace. Mutually exclusive with ControlNamespace restriction of Cluster resources + allowClusterResourcesFromAllNamespaces: false + + # -- NodeAgent Configuration + nodeAgents: {} + # - name: win-agent + # profile: windows + # nodeAgentFluentbit: + # daemonSet: + # spec: + # template: + # spec: + # containers: + # - image: banzaicloud/fluentbit:1.9.5 + # name: fluent-bit + # tls: + # enabled: false + # - name: linux-agent + # profile: linux + # nodeAgentFluentbit: + # metrics: + # prometheusAnnotations: true + # serviceMonitor: false + # tls: + # enabled: false + + # -- configCheck provides possibility for timeout-based configuration checks https://kube-logging.dev/docs/whats-new/#timeout-based-configuration-checks + configCheck: {} + + # -- EnableRecreateWorkloadOnImmutableFieldChange enables the operator to recreate the fluentbit daemonset and the fluentd statefulset (and possibly other resource in the future) in case there is a change in an immutable field that otherwise couldn’t be managed with a simple update. + enableRecreateWorkloadOnImmutableFieldChange: false + + # -- EnableDockerParserCompatibilityForCRI enables Docker log format compatibility for CRI workloads. + enableDockerParserCompatibilityForCRI: false + + # -- ClusterFlows to deploy + clusterFlows: [] + + # -- ClusterOutputs to deploy + clusterOutputs: [] + + # Send all pod logs to kafka + # clusterFlows: + # - name: all + # spec: + # match: + # - select: {} + # globalOutputRefs: ["kafka"] + # clusterOutputs: + # - name: kafka + # spec: + # kafka: + # brokers: kafka-headless.kafka.svc.cluster.local:29092 + # format: + # type: json + # default_topic: topic + + # EventTailer config + eventTailer: + enabled: false + name: event-tailer + image: + # -- repository of eventTailer image + repository: + # -- tag of eventTailer image + tag: + # -- pullPolicy of eventTailer image + pullPolicy: + # -- imagePullSecrets of eventTailer image + imagePullSecrets: [] + pvc: + # -- enable pvc for + enabled: false + # -- storage class for event tailer pvc + accessModes: + - ReadWriteOnce + # -- storage class for event tailer pvc + volumeMode: Filesystem + # -- storage for event tailer pvc + storage: 1Gi + # -- storage class for event tailer pvc + storageClassName: + # -- workloadMetaOverrides + workloadMetaOverrides: + # -- workloadOverrides + workloadOverrides: + # -- containerOverrides + containerOverrides: + + hostTailer: + # -- HostTailer + enabled: false + # -- name of HostTailer + name: hosttailer + image: + # -- repository of eventTailer image + repository: + # -- tag of eventTailer image + tag: + # -- pullPolicy of eventTailer image + pullPolicy: + # -- imagePullSecrets of eventTailer image + imagePullSecrets: [] + # -- workloadMetaOverrides of HostTailer + workloadMetaOverrides: + # -- workloadOverrides of HostTailer + workloadOverrides: + # -- configure fileTailers of HostTailer + # example: + # - name: sample-file + # path: /var/log/sample-file + # disabled: false + # buffer_max_size: + # buffer_chunk_size: + # skip_long_lines: + # read_from_head: false + # containerOverrides: + # image: + fileTailers: [] + # -- configure systemdTailers of HostTailer + # example: + # - name: system-sample + # disabled: false + # systemdFilter: kubelet.service + # maxEntries: 20 + # containerOverrides: + # image: + systemdTailers: [] + +testReceiver: + enabled: false + image: fluent/fluent-bit + pullPolicy: IfNotPresent + port: 8080 + # args: ["-i", "http", "-p", "port=8080", "-o", "stdout"] + # resources: + # limits: + # cpu: 100m + # memory: 50Mi + # requests: + # cpu: 20m + # memory: 25Mi + + # Service definition for query http service + service: + type: ClusterIP + clusterIP: None + # Annotations to query http service + annotations: {} + # Labels to query http service + labels: {} + +# Logging CR specific serviceAccount annotations +loggingServiceAccountAnnotations: {} +## Syntax ## +# : +# : +# +## Example ## +# +# root: +# eks.amazonaws.com/role-arn: +# +## Result - added to the Logging resource ## +# +# spec: +# fluentd: +# serviceAccount: +# metadata: +# annotations: +# eks.amazonaws.com/role-arn: arn:aws:iam::1234567890:role/my-iam-role +# + +################################### +# Rancher Logging Operator Values # +################################### + +# Enable debug to use fluent-bit images that allow exec +debug: false + +# Disable persistent volumes for buffers +disablePvc: true + +# If your additional logging sources collect logs from systemd configure the systemd log path here +systemdLogPath: "/run/log/journal" + +global: + cattle: + systemDefaultRegistry: "" + # Uncomment the below two lines to either enable or disable Windows logging. If this chart is + # installed via the Rancher UI, it will set this value to "true" if the cluster is a Windows + # cluster. In that scenario, if you would like to disable Windows logging on Windows clusters, + # set the value below to "false". + # windows: + # enabled: true + psp: + enabled: false + + # Change the "dockerRootDirectory" if the default Docker directory has changed. + dockerRootDirectory: "" + + rkeWindowsPathPrefix: "c:\\" + + seLinux: + enabled: false + +images: + config_reloader: + repository: rancher/mirrored-kube-logging-config-reloader + tag: v0.0.6 + fluentbit: + repository: rancher/mirrored-fluent-fluent-bit + tag: 3.1.8 + nodeagent_fluentbit: + os: "windows" + repository: rancher/fluent-bit + tag: 3.1.8 + fluentbit_debug: + repository: rancher/mirrored-fluent-fluent-bit + tag: 3.1.8-debug + fluentd: + repository: rancher/mirrored-kube-logging-fluentd + tag: v1.16-4.10-full + +additionalLoggingSources: + rke: + enabled: false + fluentbit: + log_level: "info" + mem_buffer_limit: "5MB" + rke2: + enabled: false + stripUnderscores: false + k3s: + enabled: false + container_engine: "systemd" + stripUnderscores: false + aks: + enabled: false + eks: + enabled: false + gke: + enabled: false + kubeAudit: + auditFilename: "" + enabled: false + pathPrefix: "" + fluentbit: + logTag: kube-audit + tolerations: + - key: node-role.kubernetes.io/control-plane + value: "true" + effect: NoSchedule + - key: node-role.kubernetes.io/etcd + value: "true" + effect: NoExecute + +# configures node agent options for windows node agents +nodeAgents: + tls: + enabled: false + +# These settings apply to every Logging CR, including vendor Logging CRs enabled in "additionalLoggingSources". +# Changing these affects every Logging CR installed. +fluentd: + bufferStorageVolume: {} + livenessProbe: + tcpSocket: + port: 24240 + initialDelaySeconds: 30 + periodSeconds: 15 + nodeSelector: {} + resources: {} + tolerations: {} + env: [] + logLevel: {} + metrics: + # Ref: https://kube-logging.dev/docs/operation/logging-operator-monitoring/ + serviceMonitor: false + prometheusRules: false +fluentbit: + inputTail: + Buffer_Chunk_Size: "" + Buffer_Max_Size: "" + Mem_Buf_Limit: "" + Multiline_Flush: "" + Skip_Long_Lines: "" + resources: {} + tolerations: + - key: node-role.kubernetes.io/control-plane + value: "true" + effect: NoSchedule + - key: node-role.kubernetes.io/etcd + value: "true" + effect: NoExecute + filterKubernetes: + Merge_Log: "" + Merge_Log_Key: "" + Merge_Log_Trim: "" + Merge_Parser: "" + metrics: + # Ref: https://kube-logging.dev/docs/operation/logging-operator-monitoring/ + serviceMonitor: false + prometheusRules: false + +# -- Extra manifests to deploy as an array +extraManifests: [] + # - apiVersion: v1 + # kind: ConfigMap + # metadata: + # labels: + # name: extra-manifest + # data: + # extra-data: "value" + +# DO NOT SET THIS UNLESS YOU KNOW WHAT YOU ARE DOING. +# Setting fields on this object can break rancher logging or cause unexpected behavior. It is intended to be used if you +# need to configure functionality not exposed by rancher logging. It is highly recommended you check the `app-readme.md` +# for the functionality you need before modifying this object. + +# this object will be merged with every logging CR created by this chart. Any fields that collide with fields from the +# settings above will be overridden. Any fields that collide with fields set in the files in `templates/loggings` will +# be ignored. diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/Chart.yaml b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/Chart.yaml new file mode 100644 index 0000000000..ee00db09bf --- /dev/null +++ b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/Chart.yaml @@ -0,0 +1,10 @@ +annotations: + catalog.cattle.io/certified: rancher + catalog.cattle.io/hidden: "true" + catalog.cattle.io/namespace: cattle-monitoring-system + catalog.cattle.io/release-name: rancher-monitoring-crd +apiVersion: v2 +description: Installs the CRDs for rancher-monitoring. +name: rancher-monitoring-crd +type: application +version: 105.1.3+up61.3.2 diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/README.md b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/README.md new file mode 100644 index 0000000000..e0b63e0268 --- /dev/null +++ b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/README.md @@ -0,0 +1,24 @@ +# rancher-monitoring-crd +A Rancher chart that installs the CRDs used by rancher-monitoring. + +## How does this chart work? + +This chart marshalls all of the CRD files placed in the `crd-manifest` directory into a ConfigMap that is installed onto a cluster alongside relevant RBAC (ServiceAccount, ClusterRoleBinding, ClusterRole, and PodSecurityPolicy). + +Once the relevant dependent resourcees are installed / upgraded / rolled back, this chart executes a post-install / post-upgrade / post-rollback Job that: +- Patches any existing versions of the CRDs contained within the `crd-manifest` on the cluster to set `spec.preserveUnknownFields=false`; this step is required since, based on [Kubernetes docs](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning) and a [known workaround](https://github.com/kubernetes-sigs/controller-tools/issues/476#issuecomment-691519936), such CRDs cannot be upgraded normally from `apiextensions.k8s.io/v1beta1` to `apiextensions.k8s.io/v1`. +- Runs a `kubectl apply` on the CRDs that are contained within the crd-manifest ConfigMap to upgrade CRDs in the cluster + +On an uninstall, this chart executes a separate post-delete Job that: +- Patches any existing versions of the CRDs contained within `crd-manifest` on the cluster to set `metadata.finalizers=[]` +- Runs a `kubectl delete` on the CRDs that are contained within the crd-manifest ConfigMap to clean up the CRDs from the cluster + +Note: If the relevant CRDs already existed in the cluster at the time of install, this chart will absorb ownership of the lifecycle of those CRDs; therefore, on a `helm uninstall`, those CRDs will also be removed from the cluster alongside this chart. + +## Why can't we just place the CRDs in the templates/ directory of the main chart? + +In Helm today, you cannot declare a CRD and declare a resource of that CRD's kind in templates/ without encountering a failure on render. + +## [Helm 3] Why can't we just place the CRDs in the crds/ directory of the main chart? + +The Helm 3 `crds/` directory only supports the installation of CRDs, but does not support the upgrade and removal of CRDs, unlike what this chart facilitiates. \ No newline at end of file diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/files/crd-manifest.tgz b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/files/crd-manifest.tgz new file mode 100644 index 0000000000000000000000000000000000000000..da3534e6f3da2037552c6dec84bb7df4906688a3 GIT binary patch literal 331364 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∨vXsm8kTM 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

@uoPw;HJpNf!wK#H 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νP?Q}o;Cil~Ao ziHT^PmW4xAw;>9ZzSht*IIalw%Fy`hGa;{~CK{>_KQNq9p<#=BG-i67+c3j{Vo}bT zF0uf{9e;}GGB(xEeJCnGVP|x+FvC5e6L|J*;3OWuDtN8R@2OEtv!+YP1&tPFR4~#w zuFM>s3)eGyVf8i>JBPLVKH@Ts|7QNHKmB{dLYo@!%pdf}Ggd@rzCGj2tp8cP zWxIUG{=1ze0Bc#3gsG1vPEII9ne1n?P4b`UGUv8^2o#kx2PAuI4zG2m*y;#tIja@Gu?Usg# znam^B9R%IGq1_gtjw;bT8t+Vfo69oWh5??Vrb81*D=`{OLgu<%W7h?0Q0t|ju|9YQ zuXremfwDfzg4W5^O#Ic_7E$`iD37b$?RhG>bU^64>wNJQBz2q ze!jwA0UE)59d2v$~I^R%j86uiaK zOyr>VTR)s&pB2U&j+a1PT_8AN2c@Ao<1JBD5hFQ6YKHKPmQ}SkPA6p>(DfkLt2LDXMl9jU11;WOjCBN_9tW=qD=#(VEL~X($V-6botU zA8WSGvIR?7PLq1~1{>;y(RD_~3!c)fDerU-=5=Z-lAFGZps_KHz2zJDQEB8KD^L|Ld9!U ziZ?G)yu;$eZM*=2324#pGJ2%E5h&@cgtM^?EnTh`Hm)cKBzISMT}Uy83Z|uMU#?4= zh`x4Z-RYBUQ%$i>HZ2_C6_PNa%A9qil@LF*#0=~G2fM!nXZjNZxL(9 zx~(>DC^fbTr!6$P1vR!Qcq=se(9{@Ub!*O-vrj#54lJ%*xeY}VEJW$9>fT*Op0Ju4 zA(1OG*i86NqP3K|!RsGC;MfP4%x;Xet{OYo$sTU(W$PulHg zfqz#-7iRQdHTe(dVAcM=-a_w^J(v@~x7&kpXe$}_+yxDQ3qbjzE#lPYs<3Jls9aot z@L3DA5-!}X-EzN*H-l+2OY-gIE0h|oP4a}#D%tTAQOVFhk+O7(hRQahp+|uYh#oF0 zq~vkCuDB|!w{#_>7h~vFFK1PBgJvI|FkW3j2b>M2h(kmS+GzP5Ynu_fW5S@ByW~Z} zMU<4W9R$aOf`i_&oze9nWr+IYH-`sV_Y`qfOBEGu>5*Y4^BS9ghz&2c$Hno)wv)Al zrwM`sfZwPT4nD4>AKS`F8@k-7!OXF?vV@i*Y5?`X=kO#@TTWax=c%FOR&QHEGMdwr z6%L|Au{Ira=jjv`P^f7dYlpQCfP~^&^%iokV<2NSww;e-tMrHN((HRkj_5hJh6;CN zJo*V+v$t8~f~a<5K(f->IxO|ETC>;G%J{W+(qop~zZH3N4w7i~cvD4fo+|n>XOR0! zlk1E{yO7queRF+YZxvXbNo->9J)yDn6yLMyLdveH2PZZ#e9ntSIh{l@^V(G}PvjZoQ8#%1C3Bxqk#QM~L&%thOr75lNL~|;weQLYWGAgdt zz(@3(9Sg8JceFihH8G>IYpHA(wDpgwIUmcM&uUe-JSZvanLCC`$>yh>@vPNzo+Nm6 zTtUT9&-MaF0SE(dp~gIMm^k372JuAP5u0KIoo2>8lOdzvBJ>u5K= zGqU1815IQ%J~YzoM{9^A-rSQ$4&f3dTiaASzBD)n=TRg}(F&^2A0WQkN)xxNzhy14 z6(Kb=eC0rxTG9f#5+W8GVRT*p;~WBAYgh#NrSb=#vsB(W!)aNR zdD~5yvxHH_CdVDDr2U$Kc)C_(->{qI!nA=^FRl%umR#KfFRiCb-KYVnuepEa9m~l_ z7gG2Uj>E^hs>IX{OS6O)tnrYN;W?Fts?JP3qq9HQ2*eH5ij>8?3F>s%l2N26QRq5^Q2QDBIxjLM@U<6lS_t=wExja<$)>XLrBOC-Evhdnp&k| zgJ;o^k^|;K(;`>y==TJO6YIa_znW^Q;KA0y9N0Y~xCC{pDeQOv{oHu?1*I+cS^IT0 zxO=Pd`1$5|txs8T&sbNz8DL#*ovQl~RCb$ps>)O^m+9XC{%G}RSiS^VKXQU6^)qL~ zEZs7e!gvK9@|-+6AcGB|40;TV?&8_%zO;>Oe_=ZKBrNA;P;msg{R^NbKL-N+_T1F@ z`j56|Udx@g=?&13KnAw{ zi00IdLyQ~@m4K@sUycZ$u!;T4HG;UzdTw*9ngvwU-849=VEDeG z>9_jvZ+c>oj6MFFmkR#(k7z>eX#C^K`@Tx+YWjV&I9s?#>SJeZ4g$FKMZTP1#mkid z@0@8SVqI{yD6}SGS}*}=Vx9Fvh&6se!v@Smug1x&f*cr;LQ0ZIG4H8dbS?<{#1))q zTvFH%Y9JCV0E+H!HJz@bRhZ}(LKa^*YWCcYpbXzhZVSu+G%v*Tbk;~S8#P^$lq;

WNXC`vI7hIJIvhj=p8~a*Ix>WYsh;JK&b*A9Af8CeO zlsQ2siGj+eF)Wq8^y6g@^#;}jBMuxOs%AdAsKltm~7sCe(7sScvm3`M{ z&a3Bj7l!WC+qJPft{toS3#PgG(D=jgg-HnLUR!`veGtxlLjHZ}U!nLocRKrK&jTK%SIjj>Wvc4I znXPIMBEWwI?)vBQa6rbzEdZ*gCK5KnO{0H7y7JTCmy?^HzpL}(-`1G`f9vm$HrsQ< zbpk?TXXMyF{c}>B+|UvfdncEqlS$feXUJ}`HyEM18TFXzi8$u=9_PBP`K$HCdRNQD z47-m2hkc-4juU7!4ipKVRGp3dODps zE_0w1YYFdosVL-kwO!QV!CEs+wmflI8GqVC+otbFv0+GKbj^FtDsZV+6uQs`&)-Ie z$PX{x+1E2Qb^7Y%(!o*~5hY!naHQz)qYGof<~ItEw3KICAF4jSW4A4-Llu86mCywX zZ;JVlJ&IWQUk3o3*rXJJNXnw-{9a+zy;@441!^ zHOQnx(ljcR!68SBZ!B7OuyQSWx>e8rQ2LW-Ts;O@prURFC|&y5M5*@_sUztb>;CXH z6NqosJ{tAerazd0KjJjws}nYNw_hB8y_FvGJuyN6Vt|cpW-tZWApjvi#Zx*200~3v z(N^;N?M4TeJ=74mRZS6R$HzA;y4LB$V}@But(vv8Fr9y=h4MmW+1bPXgl#mgQy)6J z0SsRBGl8du@LfxUDBuT1VN`7rRwWVT`EB)d!kA3=;ymU~XFg6+kfx(0F94ldibbx` zp_Gf5!DylxMfq~6jo?AOfBv+Ea76}bNolJ(Y70I@_wAe}KhVfk+3S4plNZzf+uzSN zt1A~#lw=|P1PKZzQpneFWJ1I^gd`0gSNeZ)!m+IN3z`r)41;IVVscG~366~k9z@4a zpA;rEg{kVj!RnpSj{P0RXMmVlqY?U16E~;>b>tofrFMP>V>o1ZMuYZzG*C?({!;&>8&sS6JtgdXkc0&|Cu9Cv77?m*UBFqlB^X=xoc+Iit&OAH%-EeQecb|BK8#kcsb-Ya1 z)KTzr;V+WjhbhF`r>C7vuQ4tEBC*NL+6K1;UqCvy4)m?K3H14Q45n1TYvy;M!CF8Z z@6~%%3*`)}<>_#$<&|mCUNklZ`@>qEqBhCy13jqbIJQ&@ZrVn}g|3TFKY^aki5s?F z!TvhWw#vGu^A4a4cg9Lm=uD>4L9rOCxtaHI_V9LH=924=Hux>)EpP*!pRrj-TKAn9 zl}3dpwUnbKO5IfGTd<%P`}g}|VCGujf28rf6NdG1(|DrhME)xFP8SUSR%zofV7e7r zE`LLAIiQv;lM`%Zo&m6Bd)QKE4hJ5VQBqNB2M_r3<0g`pmBa*(Kf>9@$ken~WS^2M zOSR<^rIDh4UcYF~?Gb|Hd6*kDivN<<*x=4{TiiQ80X#(IZm!7kq#V3jO0LB@?Vf%l zAWjGERyWdMgEIOi%*Pl&sQJI1)P7v9g@PW32*Mc%yJF!+x!&O}gIT~jg;oVQfdyH=9!#rP+XdE?N=K4kXQu2U%?O_*fM#V|yu3x3L9GB3CCk!p` z_|0RJkwiQ!OxH#DzZq<>HnkD`ESc zl|0`pv;M57I(wsnQ((KV^c7 z4qI7Y6hnYDO=zh~7Fv=--AK|rPV3)A)Kl%dGuJUyb9@%zjce1|G#zJ%hFOo&%pz&l z%GTIR6Ugs5cr6ZnkqOJ@u>P?NIzLIs3ks}x&FIL-_u=~W1>F>YMXnJHOyAc?u5WgV znD+DkUqJ#nT|S5{{iJd^)%7kKQ+a--SWna&ga>Ljuh~-lxxwuP>xAs+S=MvUnK;}- zf?75U6`J$d-y!3Lgi8G8Jl}(@f7%|ReKSbl44spW0m0SgUO32}f$PB`W>Jnmgb(eeZe)?;jq?je69 zXsGuGzpRLGjDIu8wPO;>Kg=c^Q!DTs{rfpdtgMV_>AO1S!SxfKRT^)CALb zm}!C?50oqzC2ifnZV`oT629>f;rhG=?WPrA$WSwpk!7+38iF7eTWvNV$pNaSpuAHJ ziKA^^K>__YnTIy_dy0&B%MdJ$oWV@*)8h&EmuzhZ`BD*O$gh$HnZqpdA>poj$PI`# zomNSP56Tq784Pf35#Fpq8e6!Pcx$ii25^mutW5f81iBUc zKVE=QF$IS?7MM!#ZaWUh%}bA}$lUO89W!RwI~QPk2^1YS=AS^VMwdP;owQLtxlAWq zkw$pKJgvB{yFvM*o{8p)V=Jb;MYL@_ZZF=^>^R`)IOCk74!xDzj)Z zQX^V}D|aK>y=AW-gDK59jNJZzn*YyDY+Z2X45oDWj2%fzEgyZ64I z4ta{H3dYEiQ=Fw+Xsbl}u6>7?rnTOHmaXw`_&9SzlWxvsG$l+=8jQz@c+sn=y~r@D!KE#iDa)I*3VWt$G%h-u&;;^-q&=p zvT%T#q}8SQ%4+klVSdfa1>*!-L6>VGNZ={&M3E&FAGy){BEJ^)`&2aA#|X^VFIpq; zZ@(^>FQcCHe^~ERtaPrI94Oss`5ZKIbQ7&e7-A8!RwT zkNQ~P!G3(e20y#ipB-x^I#2lzgP)}3XRG|<)o@Aqcv4?l<#(~p)x3|sQW|+GtJ1>R zD2e^A`tuFyd@K)|@fY};x?m+mLT(_Nfw5GLIt`w_nuc8DZ>lJ}T%omV>HE9%E|4(6 zKnUtgyZ9<=YjGpmVrf-0XGY^oM){MGORBNf$Up>B?BhKv%nrlDd8OF98MYzLNYzrD zmZCM#D-($|p3BrU*CdjxNEYhJ`8O@Dod`A?$1>zaV)H;n`fW9s8+pL3j~b!4Zx%`n z?@{2;pSPSi1dnEUObT9!g^2cc`NG$DJ>BL}Yu0+CM4~Vq|1V&h6^HV>Nt!7QF>k9!v z6|sBiRe8Rc156|rLD8_&`T&?)IIG?*91Mt{Ws|luE)c(fKiqYg1RNgXKlymi*>_S(4@N|I1os1$53PsV5#b{^jc;p+a^2`)k(R) z0WZ*KfZ;jW>D4XXLs2={KVCe#Bwc1|4dVMG5-&oXgcy3_VbAp!z*14&gd2OV3B- zMpKr~QpoxFx(2T$klCoN)Nl26DZ@)sajZtK*N00abb$5oWX+ydC(sz*$Jj-LDosEV zqdJbo!vf4KztZ2o28RPapTX23DnkR{wrQ8fMyq#kP+jKLdQr7Y4xGXVTS0ktQcbek z{*oH=AnMawnFOZdssRSR#3yGXk~7IhGzTN9MG&Ve*H#gruSL~_XUum(lU$N* zxLn$zFL4sNE)`co=Fm0l2P40Vk(_o7Z-@J%ga74CzoT7Ji-vu5qAfvOy#5;f z>7pg|hwAzZwmB(OX#nK+6^vjOmZ5rrIRJ}YMJ8q&+ zX)UO)6^T@TDf_kA(0(ZSg&AxD?9?PFuE0vlm?1Qbx&D!6<7V zwTFC#)MS>5NGW_rv4cx}A=PJwj68#xT!@IXdVfzLB5dt6J;22?7RqYqZ@oINd+#Uj zr-DC_HD0enm#>!|2NOr@1`T}M_pmSJ*IR$Y-+q6YO2OONs@hbvjfd#ZI?$BFkOKZXSG$m)eRJqwmxu@C%JZh8xOsq z$4W0zhb(tQw0V8PdShUjK7d6 zvC5rHT^_BziM`ZyQM(1szbZVi1H)eP5E@jWqTVs(? zIDQ|)V{L!d9zx*+&4aOKe+zhhZ{xPb96{%O&y)x%+XeqGP0aZ9*;(1u)h`!5Ud@j2 z^#tpY?dom%pFA<5QDEkQNz^_*J@4>Yp#Fr32#k6OeEXs@9g3tmkdP;@Jb$;n0x1LC zt#KY5E;{3$n7XafnY}bF(kY|yLh0WBW;K8v^vJFmFrIE*gsSll7)in2d#o@4?-YDd zHdk^b-cJ1K?Zhyb1w12)d_NvpN!-0Hw5-%-;O+QE>`<%HddM7~e#}?yD%W~J_5SG5 zvFNBd64KkR24WVRotNhp)K-;-?~+JxZ?bUWk2(-2m>^V6o)aLC)I~pyRl4aSb4gi@6{L&b*@? z0~X#HSc}+F_GhT1MYKyBQ-!mG|HzFAqWr|?ViI%81K0z*;8i3%19_RN?BR`HO`s;yo|k!X97w^&--d=IJy z&~%EveZ(6_HVE2g;N$n2!Anu%scqJajh+Nr)JScs4IxVHvrjA!At?0LCHSX ziKwoVjCytm47u=KAwcf4S;-Rv5&q9>h#U8LZ}alK%b{T%G6m7saol^G}^!8>N6>So?W(qw6Px=71%1E^J{SW{iiD#Q6zo^6Fgq5OK*YHwv+7 zVpgR3UmT-ZtwHm~^V5p;*1E-2vMkrx(_f3L#k*|g5BX(Gz30Q%Z{@g)P*+;Dt&T_R zsIs+~ic7Oy@6o*cSC_`F<0iG~|AJ&>*x-2FKW{-}eS*g>ht)62>w>Z`_l9*{bpvsX zR-R3KF74&`7FQwRlq1FBWg7S}&*z>%s`#*u-Z!k-#=VxrsQSfT$REPkr$BRpa+n5~ zF|p`WQBbTsMk*oC(9r@>jxeC=MHM^frzBB3I=+}a{fW15TFvDCE92m4q{pm=RBbq&z zFnGfNa|O7KZh>I^& z0D`fQVY}(zbs8fX*h*SHX_G1gkY`78;Q0yqKf;I~fIqeAFWV~}E z?wA7pirwE1a3xUA{w=!%2FP8I&uP#gp)k+Jyl+TaB-LL%6>2RQpb5##4?>Xf6Fs__ zPuMiDPZ8n+regzI@hvBW5kJWrRTfjq3ThnrY6BMzxsB%diymusbo3Urz*Qju=AKIr zJJ2yzB`-NsYKq%WtnS$U7bfQJ_g>^?kj>9FFQ%DE=1J5mRNr zxj|d&QcCNa5x#;I>$c9(lPCvr|OgP~g#tMh$?>1+zI- ziECq4XJ~Fjh%W%JkknXA50I3vi+(lAz{KXm-Z!CrS>%& z-O+Akfeq2i2?l|a4ct9XIut_HItl2iZm5aFeUe9Q?1s{c9U4_X>;SG%c!QEo)8{EToQr7v(-$u;`!!j(pv6_ zVIx`tO;!stP~!KMI9$iy`u%Z2Q2|?0nYTcHq;@f>R`1wxO2xKhEzkJM!{a5 z879}{$PE_J8j*S&0_*!|GU8!_fT|oadFD7ewD6F0->eBjYPFZl3&QbPvrtNpQ(Zc`>+t7!6~2IJ0Tl zB=!qP5Weo!=)+7Ld4mWn(LbKBUs~gsGz1SJFBb>kAaLI(^8*FI^RoSwdj;k3cW$^YIenJ?=-~pPlpdndzptquuoiDe!)DQy^n^tJjnD zmEH9!p-*CF=C=iQ-zX=WbyAQv?j1>SLN*v0vw|-fQrxiMV}Y~w*$)N_ZXV&JDqoQZ z?f6b1raRf~4Gi}781i*CbUD=H#&)lIOd9_@iB+%!2F%GS5n2gu{cp&xzv{9!Ha+it zP<7xd13Kltl!>QaUs;;LSSsqzS1p-K`&L@}hDStDn(c?h#6`PU{p!fpXCcNrJd|}_ zOn_9xPn2sED$KUGy<{hAK~_g_O|~>b>Hs*v{|AmhaldgOr*0)Wt^cQU2KiAQ5?fE} zfJ|kTjH@4BO$eW{nf;e*BxVUKU~Wq+8w^y`-!vr3!0`P*H^0?Sf7TNNB-rVnJrLTz ze8Ld!p2j~l-uFZ5oHqFBO2*e(gT_Ttp9ZaH5UvU7JsSWsInzwUrU02VE`1wl!CwGO zT~8i{eoXK!mRX1NS6GcxfSdSC(=1^VQbDV81B=JvS|=vC9F6_*tDgBG|1h}whw zHR1evT7`*zA!PA|qh>Gd33S^#$zxK2LQe%L1-dW#8Z{d=Uz3z8tpUt5D@11GR#RaR z@H~;xEsGI)df*m!eZvBPMb{b~76uLt5HT%?AimWrfm2bmFz!s6d=TBjilU&L#n7lJ z$Ub<&Dnxq|$*X5A;os&T=p>zy_gaHalHMBEngbXOz$9%57BQu0zII;Ll&;N07G(kn z9eq=`W*f*nS4Cb%1scWYxx8h9L`kU%miH57y=H#SXgoz2JqRB+xRlBr|CGi+7T>tL zp>NL8Z2?^rEQcEGRFOFpbLg{v+2@0++YiPnyKuavI+uMyJZ;1UU-w)4$9QEhI@?H^ z=#*2&t0-ha4O)Xf<9010neiH0_z$lJdcY$0df~tXRcOjH$@o~=A9HO@ra;~A{Vxp5 zK+nlQKNTPCcc%pwZdbjTLuB+qgC1kj$B^4wj(4SHCsi;}{7^{^XuxKo;CW@E>*Xp0 z5QAWMN`Xh9zE37)nH3e@sky-h+bxU?W1v)Bevl&6XeX_c7-$vuT}g9O>6^HJ>%xu+ zG#zO+^-jjaua4cwM)Q^b0kP5*Xu9|UN#P9-Qr0lj6}=mnDn45ZxS87wE5`l~2Q-BN zP20*()Sm#aB0hn>MgQd?*$AJl{EYU|ToOgqL+pOldX>}YOXYaX*T%CDvWj2ST685a3R*X zM6W$E@RU_hj<09+(;T%X(7G0KCnf|^z|)S`zWk+yo+le&Z=Y-BgO|Mbv1Us z)<`|MxzS(cmg^YfaIfLF04!C;dysdV&v<5_pNp$YL_9ItA;N;#``rcKAtLj<%1=5c!}z9WnY0#mgB4q&ZBxO(O^y1l1)JfxZupqn(K zg$eMVpp@f_B;ur~CxMR^xcs@CdP}n*h@CkB%)$wDM+-F{bS=`dkSQ&A1a>mMAW~SP zc8Z2~eYUIz5pQRZ3T&8b=&@)Q+O}FAZ$->%*C%hM=E)|(W4%F-DddLaj1it{^?{0l z#C&0{F6GLt_U%oWCideB5D=?&(6pE&fVglkD-a+oh#?m?foD?hF6cTn?P@lvchKX2 z6Mfq5S(51g?c;+3;p3h2;!7cO26^(<`ep(vPvcx>nX#LvXWPsRf=lu{lMChY7DPUfk$_oo`Lu>UO zidwaQbEx^k#dWgJS;8Y;Bx^EQN1^$E8hOtVUXlvJQ(NvrFWl7DL@+jAH(mn}%|3$# z9*6WBCKtje}vTwUh7#vLR zlmp;l0x78-M5Z;XJk(^=oqOJVf}^j<*39UEKxmrJcu<<=Gmgga833(mKH(rXBN`?+c^yMrul43VC0aXIL&AOAUVxvtMwiR(P=)rtoFe{cAC!-L3e_?-YW=C z^9cmyX+EPEx|!cL0=&1V;V zaWpk;$A*puLbTcOkwA%>&v8MDn$Mv$j@^RdjH&WfLeVF12qSm1kJefT-aD1o#a2f< zzMVGG0|`jJ7;#v!>5Ia^K&gYSd1q%{4q$9bk--}O(Ds3s^2k;AHq5_+;x{6~xawJKnR ztd9^fR1ud#b;A}k=)o&MsQdRW$*7vU~clnklOs!RcVX!W5dZ za$p0n!9#@iKzDkv#u-(dse;_owZ%cB_LQKR)z!zW2ZC4e{#_CaS5=D*(=JVETt&wb1&2dL!9ISY|?{y zBG)X}P1@*}NQyg_7Z3`v6#Qq`k1LD^=IR1msgT?XqSa)eJe?Mg4XjHkytao8oh_Hz zk{33_ERtzj3SO+wLDz1vpHb^tjL>;z}f262|^%?X`gZ|@E{R=4*V3p7^C}lY-a?b7;q4}H_IR%_W+*z=H ztxay&kVy(W*MRq^Tdk_$+C&p038E4LDrH!5Oyg9wYYnAh`E*(Gn4Nn>vAf(v4CcXPJ=ZYkTeeo7%hm}nzAZ@ROR8@>crT&_TgsgOJVaQhDw3JmY7k=1s(MQA=-QP1 zwDOI@pl?6~h3mi4y@#}U>;cfK_f9IwumwAiN`^BA#%&`S?To{$6#S=>RmJCBxcQ7+ zdU{(O$H_?!6GD?>CClYdRw!h@Rv}F(HCb1L+DjG;MR31jP7NlCRpK1YG~dp-R+s}K zvTO45%%x9cIZtWMlQjr&Q1@sdb2Bq32#;Bs$pUmTpjkgiXrN24ywbp%qa*~f1@UpH zdcNQ+SHFWD4WPpTb`e0V{is>tMCvPG7E>u&(VRvF%eg9eggCiYbux5=su^JA>g`|2 z-rVT@S@xU8KTyKES3FSs2*t1(clM8gUG*TiRY6Ynk#>(^fAH3R;82XJal5-;Y^o#T zQtbiBq6$Hk(0G&od`0)y(<_){Yg2!peb$6MVGn0XFoDPfMba3pZW5tX+BSy&y(geVyuA}NaN4I;joXMaF6`w0Wpt$%}RD4w$V7cKRBk*qrfwI zC@iC`ag2_QVH7Tegkl$Mn^YGJz%m|uWi;^0qXu2s8E|F%1$hi?qK88o83i*JibwQx z41RmZ;7E8w4~{i-WSpU2!O0ITaTkOuv<0Tna4ySuJfZNbe>{%RSPUVz3<2aaj2{%5 z@Er^yu}$v&gQEfMh6FSg1!x2UP&oR}7_z`;Jo3+IAcwJtKilHZ90lp;uqZ#H*LEDb z&$cUjR8*e_Li9O4n$H$UJ|j_lwm|S1kKVI049ytSo>0V|QD{9|V3-`Cg6Jr8o^7?K zQ4}(seLM&n&x0WGJRAzozGd?5LzKp$?u?_R={yD`od-kFIUs`0<3P`OP~@Djg*rB3&O@N(jNC5G1BaT@xeeY_%ebU+1<4hi;QBl&QGk37s z7zET=(L-^k|5iDKS}*`YvXB>edkpRQHu~yV_47xJAoA|;oJEY^G1YR>15+~cB?y&p z)7B?tJW9dXap+bms+-*b?Xv!tOV?v+S*+=mWGf}extu7>lZ>fTcnC3D0#?iI) zFRVpDKhKOM7q#;to|7}1uKH1YEWRM$i)og#1^6O#kyRNZnUt3PMrJrjD4p1i&-So^K?Cppj+o1{P^snxX5Te z)H5dM%;lXkcT5qQ!^IPo!VN*@5DzubWR26B@k2}2amV71!XdBdv$E3H_MlO1ZBs9` zs;U=Td=zbG-Kb}LD6-7eJQSTxy+feBm<~z0fIb;Qg}Xm zj;0El11OZ@Kik_4>1bH}HO)-3gbF0P&GEjaJYn$;W7S&o0vgd>Zcae++MyLD1?ga&LwY4p0J+JjPypEiKWOdQ zBoW~No8z8+6mJK80fra8)Ve+L>~Mn<9HpG&3_XP4xkSj4!6?|GV({DRkuoZ+(_0VEiiQ57oIkD4Pc6mYWDP|@w1&bl0G>nCiX!=Xd zM;qR{Q)ugeYO6?*)96;!Ec$~Aqiw|);D2~!OrVwO`sMKflTO|&jxx&XNYW=tZQL?uQlnvTb=ua|#? zIF?*tE*B(CwoXHfB_D-(X=qj8L>q(!A**3k8(Wtk`(eqeCM|hcd#srTPzn1<|3&6r zQd$5PssI^1X4@~G4mo?AXcZ)$KFOg^a%f|wVREQl;3o<4S13Vx47ipiZ1`K~4Pnk! zDPooH&FO2VdfmnFbI0(C%fIgI`w0KGM6*JWx27EIr z+*!{I?aX>eTQ5$%iP{Q<7Ws7RqIFTzn3fy0ysHIClRXb%&TxZ1iuFsGQgk_f(ad*t zrB-E1#WZI$hT03}uR-g^MGScSV%a!JdSAS?3|X#GQ_mSyeN~7$W*(T5gRNsgJwoT3 zXu+x`1=atZ7ZZ}wXvKxONYHkmSJ8xOg6Opb%Pfk_y5XQP0ARf(%M-P+qMDoY!swlf zJhQC!nW^nz%+US~7u0X}wO|?l-Zyh7v}(&{;pMRu(toksth2y_p-JbivJ>e`rN8M} zVA~^>AT;l18Wv81f@n~{OK`HpHi1(q&8A>F>-{cZv|TY-Db4z1JCwOvV_5f{G%(ax zQx5c#HQIx0ZFC-(Mg}voO^jD5zzTzg39!pFTgS$0VeVbQ)dL+uDnO`4*&9f_m+05c zxb1!J@4L;Y@P<}nBo70zB^O=*iT`nB9SVomg;@WMjcsq$+yGj;OtXMeCdb;va4|ge zlBs(u%<}X4W-P4Q)3Or*EWFw)a#>VyP(6`O0gX;=76Q1+ZAO9-&}`wR&cu&^4yvk^ za3-LpK?zaZrAS#(ORt-RU=QnuDj04Zda<1zT;_)6T7gUAg%AiR!)O25wlG0qT?8+8 zJPvjtW*-G~wqO*DeY&&iUm-1Sj>ejoS5)@~Q9l2|j1n4>qsawIA12wLO8J_R8~IUu zED&%lF|f`MI(hy5tt%dTRr_2)giH;0V506`j8AZKJz0#DFq zPnBs%s4j7ZKUXZe1+m)Nl3h=lEiEWd{PI)Ddcf95#tCBu&6jLjsev>Z(?Dy6VFfHs zxWr&&j3gvG-0BOF6cJAzqU1n;L>nloW-F@32zBs&^BT7T8ve0M88}8JOYaLke?*D{ z45iJ*7?yf&s?S}b6h#O>7lv7;bCv_}MU>M_%aQPrVTvx763{{0MUd}AvNjBg3%_== zDJrbUm$N_o`|LTKc){*jKKr+SYiXxKNrmvMM9yjA2AixsP!}^+3r~$7nOI2!6A6Wh z5ckTofjCty{a!A}T9)J)5n3@))wi^`%?4H#sKJupzAEA~x=2!&IxAwpFI?PERlF5N9#_pF;q zZZmLR|1w3^+Zotep3;H zDRP<7yx>up(A-wg?X1KxxJ4C3UTX;~?$mli_v)tEU{k!wSk5Kl3LCeJe=JV1vXP;niIXq^Usw2OUIVA3$ z#u7ErJ02BhGxGmox$KR>5o}2dUWK<=F{VK52|^WlPEMgY!qb$+sC=AR%?*>jyJ(^R z4##IW*Z_vME0O$Qs)l%rhNkZZHQ3TheSmnK@MDvT7kJJX%Of4F{7aJ>B{^HdiNdq8 z<#`GanA@z_h0J6km+R{+XEfIOYLUZvA0aViGConRC8D4y2xByDZ7V?yNg7q?3xGmh z+alaSH1gWVLGWa7$MF#%H6{bavpr`Um;efiU)a%Dy`gKRyY`!jGVPkklzb;X^rs)| zSFTqy?>h2>?723HT~A$Ye_X(0A;|*jmskljlW~v4p(S%q>_t}F01L$c+ESR9>zH9a z8EdF+x}$EE3meAs1}Kmt@K~mlcUrJRY`tTEVGjcdyALqffOwd3euf8xe%%)IHQcfv z1oV0sh}SXTt|M%P;ef8=qZA@$A3 z@`;qUWoCB{qEh?zpNmMQM(Q_8mL?cON>kLH@%L(DG4G?MoAg+*{E1_MM!9g_`Q}pe zPPwxao228<2GSAxJ3bENI7qLv75!OMT3X`UbZ< zzwmJpJY>#_*7zMg^7=|$iYpo4)YS1FR7Y}Z|6}gVb!S~GI3NiG+z-PS-xil%NeoQaVWrxBAGH+iZB0X_l1q$BC-IH!nE+>6sC4Y?!io%(p$8JT|ge19@Obq(-&t% zirVX)-Q01hFGM?|(-)n*aC7QkwoJV?YZx^ZYZ%ISK4DqJg;?LywPO@kK3VcRSEMq_ zS;XRAHUWNjIQQH}ykTeSUPQ&q;so)L4UR5cNzSL|s+N-%a73P4@6JHQKhJ~m)t6g) zP*Qi^cfJZ-OP-6Kws5s30~*-X0qzCN#4$?8mT!#+TyeH)rrnl>D;X0j1`s0$fWJ$T zXLUC64E$eCIWds&Rg%6Qt0nS`<$AOF?zszLFp+ndEhNK(8D$ABx;%W|z%h{yR}`YD zjYCrkkBjsS-{60j2{){biHRY@?C~eh&1mB@12tWl0xP$QIZq@dhRZc z&fysbRblcsuC*RMIwhB&*}oiW-Rb{HV#YPxX*UZ4e}cQcd>#&ro1-PMZoSlhh1DS$ zY-pdh<{J~H3A@n#RTA!mWFBSpIB^OTu5uvYuc?kyTYqcu7S`TWNbCe#>>U-RMi6R*B^-(u8_I<$bnh56Iy}*fM9GQfH@4vo z%NKTG{u}*G=9Xiu%0zRHAi3!5Yg1;xG>Zl=>>ezeEy1zfAgyQhnjkBw3PDr$Y=Wz* zDGbk?nS?a;#sgMI#1k#5H9K@))_c~1n(g&xgDZIASZv1ZqUy{Qk?FE0rG zqKSnS*B23%?usQtKM2}#dbDJ=8Oqpq57hK9a%x=#q+m&65_6qet0j5J$}w;E8I-1^ zZr5sU&~MDR`E0H(VEySEt;Z)iF9H7p(Ak>?vNl5)8WUG6$wDy@ASMYz%4nAlPzg)DPT{qX-DGD)__t|e@7GTl- z>ddpGe|7%l`HNG%7GIv}Rq<@$UwXE1_oW$W4_KRL4Tmr)fG@n4d2B+#&E~=kRAJO` zp4v-#0te8Y=5DnStYKio=LPv9l{x#uYvwr2yf0vAYVC5ZfAi$J*1vCD5-o3S8|R+W zh>PVbDHeRWRc5H)faXvOzASSC3yl~CUKDw|aPPrQe8E0vEaw1Z>}2mRz+;ipwS~bn z9K6iTA;?+6sA^jl;3V^$Q7CS9Pg^)pf2eAda3+eIPB5a{3cZ4tonwW4&SY-V%yJqr zH6zz$W{`$^0jRZ*{ApDb*(V}%@@bi8(WiE@><)*YLRGeoKj{|Rb&P%@k7Q~CoI=*4 zdK<%_G}Cn};I#$acA8agRt))@s;{1=nNQ1~dA7yc=+CxU04Cy0a?z2;S)2VE^C|}1 z7!NrT0^}H8y9|jemv_9o;0+hXE=c~Y#pl1g{Igz#)+AK$Wqr%UvRJ(&?UnQfCb(iW zW?i`=V?zH1W#8Ijed9u#AZpL(g>aInvV-z~ZaX>!F<|-O>Xkk>|8;Y7Wsx{Kh-)CC zjSI!1vda`xo51CQ#9V=Gz}{`Z48T-WD!`nBwltFzEb2!4!7}{x3)I@Yi5%Pb2+DTp73H#sHuGdL|?&+f|S>J&Av1K8%h?5qy+}d zJtxH~m*sNRrv_vI%@(xi3}?je1{d`C zFLoWy*43Jv-FyEXd;h)i{yX*lTlv4Mv%j9TFWpc=U!uCCm5qhE`SzL^$)u2Q2*Ef}^&dY#LReA1oHOP<6me`!ealW}A@guLmJ31=V_jKx|Xv!h<}VpYzekc@Zd zDZW(aUfbtfsgkMlum1F(f82An9SWo)Il#4n_qks&*j57xXt`MXDG4;5DN&k zh;LKB8}Vw@g_Ul%td+t@Wv_THnw>@P&?iGE=a#K^TWCaI zdKBw?%huNe0?mLh(>AYR)p&61VWQ5Um~$WzXAAKrklPN6HK8KSIB{khQRY};%#lQx z?ZlTuh%OH$wmfQ)CGY@+i7Mm86c9p&*+Phj5+=P zl44k4QDD?9Z>{-TNU~(2Dm37=e_hZ*Gp1`+kl(wQctk|ecXme@{N)1c8B{e_Y8bIp zsWN32_qbrHAZ4bCoYB-SQG0%$H!^xhc>*$N>ybU69&2-@0;3dMxZ>&-145Z zwCqI5i77IYGe73}EFHGN((Xd8921wQXS~Z>SzF9VMy$1*#e?2sLlPMc#p; zMynZYQ}hVB(_;Cqd5s|2<2dbp8xfrrUQW9ydR-MCND=gYNYvB^&ooI+UY=~7&x!NR zWk#2@J2pFf+RgSVaA@CaBvX$>G>+k0B(qBcBpI}n7=$g=6mSPB%&=p{L z*BIz~lVMx7G6?(BrCNZhI$F#^xHo>3nb6zm7*vsjHCaSskJ>YqM5h(byf5v^1U*065UFW_@m3BtT z3B1+1n6q2)sudM+U*@J8Z?Yah$?#7FEYid;z+}+PQbxh5ppU*i2;Lry=mNJFS%`n2 zZSHClK4wQ> zRW0>L=ry4g|4fqC76k z4k~M~wrYB^_0eQmWM!KW?^_wb5(W*-Tz6GP{!WFqrB&Pe11PKYnnrs2VtdFSjUNjF zLz%O7OPnb$trT8@RII&A(46Z`wjR*Il6v>*O+r<{qrW9Gy47>v8LFqP&Dt6Wa`EG} zzA$c~+JBixrmS_N3^MKP;ZD* z)bHrMVmRBmo~{0KmrNGok6Ng1OonmWP_<@}(7;9qg*(yDVa#EM7GVecI^V#C`t9jA zJbOvr2vz1@Ve)1-ZL%h88`|L@LA1A=C_ZlxMMu3P&)DbU56>p#+2@7Q|09ZpdNw1M zDV8(WQl(h1yn59Cfslq=xdt@dnI1F) z4yClWGPj?d$L#K0#q`AlhG)y@*XKeNdG_L2f9uy)N}BlduG(10+;s-HZ_l5Bl&^b@ zs2~ZWcg#W(XnwLrM`e#p6NbM_f-rbVfK7#rqz>DjEzO&k2327p@or$%D~c6`!QZLd zzxz5k?r9G5&0*u0ulKcxwmq;;3jR~c$mMIx<1>~kt_saj;@Z8-@iIQWNa@c~kT-w3 zHVyTX)5EN2FVh-wbxz#^^@{90zE1jcnKLc51PMs)?WX9Xed{fMTsBM7BI%YMs6Zy;*@AnUia zvc#eax(&4B>lM|!l%!=+@T?V?uX=#$HH|?v6iYx_X9Y$@UNbbG#xHHf%0VIoifwJ| z9hPY~4Axa`*K|JI;wjpkh5O6|4qykXbn&o#qGUn3G z`sw)-mjEI zGD#54QPVsuh5c--VrcNM)$I09pc)z_@Eo`2{KK1z*YDoU()f2Pc|R@Wv{Y=$`{HB+ z3a|%8`X03Ic-G_2Bpb3Ac}o zvarK*u*YU#Zxav_e$)v}BL$nmWa8~oi8Tw~7c665;<}*GZQoKq$*@l{ z?2`=pTa;lB7Jg&d5LSpaA!1d$FLLC^dX*kNie?Z;wQiPo7=v}G)cp)z7?Z1z$*k-x z;D|+*VFEjdk>(JM3Yi%o9=>= zryw#aY$0PZXT?2Zf;@lz{5gpE&;R2;{)5PzP!h9OAJ-aI6Y{^Wzk6>g;@d!&G$gq4<*G16p*8&`JSyD5f;OWwGO*Gsp&1HlcDrLk?Ft{ z+cK~q%+=J~v)_%oXHAA|GO+IW9Qk_1=OHdxeA+>N%%Szg8_Pxe0W_-Tuy-du2fIP> z3B5=03A;`48HzB#XZ!)Nu?V;ThA|@VTeyV<8z+e1mI(x%3&UFRXwbQmNm*dyV?Ose zGYpI+4DySI*m1KVkCVf_h-^2km0(u3FNoMF%(efn3{#p98u&6~4GXh`jUn6d7O>-3 zzm8)0+Q#a&e~Z_{Si2svr7MU#gg{N!4ubu_Wgu={k^zMLa9HdR=Rg4S8E>tN6c4i% zDNasbxx{!IZ+j^UmM>_;&U_mZ%T_F9IZe9V9OiqQnQl;wwB~P48eyLcmg~KEb$vT-=`oA-~F311{J?+i*1g+WIUU-bOniVbru7L8*X#Gs)l@uU60cTsw zGDn}i1MG}so@-GJI;D!_Y^n9n928Z93SH_Sc0OhYas4_UZ%+bHZ#zb4wq^2BX7<@X zS0tm#Lo%oe#e2Kc+Xt%OAay&8y;_#E?|GJlW?9l3I~KIuLdNW>oF`nZuJ`RNY-<}s zmN#PNy1a%1-bkT12)rIpDrmS=DOX3$I~o#1f`l1-s8`orIVt$Ouf}iiLA0u&fBjx$ zwcjI}Bm>GxNN;xyce(IMnS{G80R3h$!AX3=Xo@klJ ze&AvJ0F)!p@{_;y$=~|qZ~gD)Z#`IuP6b6tJzT*CI<*lvLWGuqWP=?gWa}utD2klV z%c7srRq$C?fs8S5tH*n`s{w;#%#^wRre^&kk9SunTXpGW=xW3kXHISekr979Q6!d8 znKDsSTUrIlq1keHb9#w8ASty^-Wu#7miIz)^oy&`tp0jNfAzkvy4atI{+-TcS=hYM z9>@2lm;CX1!`saArqo@Zx4SaAk8b_Rx&Gu_Z-0K1&h<<5p6eSk;R;X>YfQz0g!V7a zSjXn;ik+c?)6A#uFHBKe6lu<7<&0>Qlgea_;^dxOq|nxY7TYrClPbOT8VW>Vgn$=@ zkjVkB06rkpP$48`1#FxX(*AcKjs z&DVv9fG(ec44#4v`kw;_8F<&;l?f%-j3o$IGv6CwLk{N5%H&4kx6uS9lpy3X&Fhg} zC$rfJ#&%UoL|H7Re*?v=pHKhuAHP5SID`NA;_RY}&Q1dE=UM$WWg`3|ItgMw!d zY%K`}HsU|CZ?&}4>w+4(lEW|J;Olo(^0=LZjbJJyD5D0nZ$T0n(ZrEgO=tqbdSlOV zh;vYrm+ldzOfaD)3ZrIt1Z9mtsRbGcqNy7w+VGjDWlBn=M<_-8`)YvqwjvV%!f^o~ z)fD-D-n?Su+O1Y)6+&;n(L_}Vs*4$c5y#~Mf;yZ8t6brlQHN3Rq<$K0#Spicr7&@b z4}E?frDV0GJT-hH+E~b)uSDBW{Z8~td(;CdsSWUR=hL`=JG;1X1|M^YM(fC6(eYZr zAM6gv3DU!+`u|zOkoD@#*#cvj@EcIedz2_NaV4yPyf)@aFJVAcD)0KsOMb76*Om8h zRC-p+7+0tw3&vthrc0{f=B4Nv?EK6|o5BeeT2HCUaDgEzXL{WMv@e$_QG#Y_C81<} zL^B%kqBkF*$Z2#7r8aYBM%X=^=*%Qo_#0hM6)aY{ESD?De#5t-gepu<>~=u6wrkXQ zMdG!fDUV#8m0aF&#iel+L4SQyq~yw#&Ooo#tAz5DoGQl18%yu_muplq(5%@XJ>`cM zN>}+=7{FC)mi0XJaEf~eD&qE`_SSvW6xlvOnL|*Ytr5jUEUQ?L&h{>@E|qVOz*A_d zkH8-iDV9DwsXN1+ZR*=cKn>129+x!1d#8U+udXk#H@;jI(|ZP{U6ceWCS}LSH^QB{ zf-9=G{H8H4;|%ZV8ZeDbXl*T0#TJslrWdmN-bwAfW=NxNmKVSQA}Tac`sOQspIO0R};c#Y-a!Enz8pyA(xow zVRO~`J=-##;S_uuy5H`nKkLcqzy4+VXRkKaUm#j>Ao%lB;|o7~z*TAgbS2~Kj72k3 zy7AMX#!mM?2P&@?az3Ttu- zW>AD!nUF$CU{k%EQ$H7iu+Llpeitq+>u zj9TIPhh^}DApkEZBYmZ3Ih$Is3*QbotQPkgp-7BQu0zQ&+#Uf6Ja6YH$S$NmMN0*lS&ERsSM zc^Sb@Q8LfvEfZC4Oh1v{Ti7aMX7Vw{^)1RmFzljTg{zVI&|N8OT?5 zCyi01bs~f9A{{7cZZ>^?4{hWa? zyDQpVjl2GAX+5gMtMg!Hq=n{ zV6H9`8sh?|O!711nj40#=odA4&4};L;(@7cr`7~AGuv+Q_Uf;nZP6jfne7^SP-~Ya zUexL_T6f677h$uItNbEZE@J{|z&$}hK=eL_1q)cKnNzL=yLX}_RR{oWqdLIiXM;A| z`V2dwKU&+`g;?W4z4izKjap=>hocoQLFb8<9z3FPV`*H!h4kL~z!qUk0A@e`v#|E@ z{;qvEtKxKxVi1U~Y#&1fwPxz^aE%^)7_Zh*hV(lw(gk9FA;K-}?d@0uL30!IWA)D^ z{KLuw&h0;E`T$mdZ(&PKaJl_HTA~jtD*pybxfvg!&0p7d&BfIvjx4<2w{W!AM%XJ> zJddXt&5Jb}c_y_{xm4c3=0^v?3>B61pW0T!l32f-arD-AC3r;w;rgm)^ejViitSUI zrC&zPT3a6JEW?9T0FH?Fm<|0G2kkEYU<0FBc8lgFbuM^#IYqNtRgVutkph$hV?dOC z_MMYp!EB*hnh?Iw7pxRh@KFX0p>h-%NqJ_%nbF(;T*MoR*L=m8$f+32xxoh*8n$ zFcEKo4g}Ar;D`inxi#KvTF0s!0|uT{UsVpPAdrSUJc9{JNxncMPW$FG-1|w#4%|X{I*;q zZ(Yo)*O$Of&y#CLjQ7UENRVQcGe&r-)e$NR67z+_1+l))zC8-n?|uaDxYrUII+H}+ zD^lD`XFIA~Wd`nHQtvSE@-;1M7OVHtP5GkU@Dbt#ji`fob?$Sqq@a zt2vExnPtYRpPp?uH;CWJ@0fznADhpkw`R!%%V_~#MFYYM*H&{NA(l3LM(RKV8;x$> z_Kmggn7;;&j|<#md-ei14UoXj$oC4j!f|z%4;7^08W0y$asxZQNV1jJv#&3@D|-yOt8Y>Mp+Z_2ix!0xfXJaR^go~dyp+;nAb}o@n))`2jKS;W&G9p?~rjz zYNZQiF3*9% z7^NYgOdj|1$1U|jDFPB`69q?Ipz{yvO(7R@c@K0G@aQh=7#+a)b8*;=?zJm6vcyX? zG#Fy>uu6XU$VBsSvugL=C&9EED=mLEN;+^7I7@-AH-?Y%`*MlPL0Y{0NJWd?lO}k# zT$6?>9FO?eKmSiE8X2(4q2bCx9)!{K*V$>M4qA#iE}HDdW8O(Hr6DG*XH!@h8 zb#CNy?Lh2PSSvFCw1N1b|Chvilmqyto}XH)IKP=bd5bkKV}4`FR-3!~KL!Tut_r!5 zOq`IgYJQ_~gxowu%ddGARrqD3GpguJ?)op8j+wZuDh!e`zQpAbHg+xt&*lN9C}Pf@ zX^*W_TCH5lz+Tc|&D#ldlu%}#6vCTVU=VAY(6Uk82xxbD*iU{tLK`5ct0v>KE}EUx z!YUrwleBYNTv=Rg!Czhx@(6K?mP^YaRc*X`5!x`sP7TIdam}ab+>NStW0`A9g{v6p z%grWsKiZc*)ev9c4g!uVn_qnB&PCu_5TXdma$|R70%0P8B6AgHr2Fg*8!;b45JYOz zF}ovASVqAA%v$#}KW(HG`f{U|5Lz_;@zM~8b8ib_k2^ff(VAOpsUA+ki^L_FX2^W{ zHWdMvzJ5a%2P{Tu{~8=*GHB|-s_a^x2&?HUFFC!7A%{a*E3+SjIW!cW%1T@7dpmO7 zm7lg%}Z*>@iE-(*S4FFw&O=0!4gdepzpDnf;qJ;x6uOx;!IbB;cJa|DcaM z2Dg1tT0OGV^elV$n`tx#(NGv-A~^4Fib80shUnf-<@RcRYWR;T?9uW+m8{p;VjBD^ z&H5!U+zS>O6FYPj4r9LjZDmCVqjq7fM@5={R=Kp{h4DF9^a3DY?~skDl29YvOfmgV zRz?V63YXD>n=KYW=?|XC`Tb6vHa&Kk=1JpiTtJX@uE31CbsPbeFajk+s6TW&1!m%I zTX7?m!b?2&k4P4YDFmsV5~?VbP{&Q=98b*_5gAmvsEsC=h$yn8@m=U7eKpB)xrvC6 zK0b{8;X|6~@5zTHF!N5;lniTy^Lu%arZ`x&t0v7btDRm#T)^`a<84%uHX{#kMILyj zes!P7o=T=Z>Hmpj)vK(gbJ_cF-4chc238^94JPI;gREGqIR;VHIba)k*$M~OHa{;X z9N6i<(VvIqv$5W-eGP#8S_h*m1W{GvpSU;X`GK?&VegtNI!4e|TH8dD=OFzfDSt=f zV7Db5VL@sxR@dyFDN!%4V0vTZB3okF8u|TFzM^Du3l^K;lRtt}pf0WB=A{RFV0{@Y zV9xDsrjIPMh436d<|L_ARfbA&Q*S+~JjG?Eg~6_lvr{T~mG6JRYfGpg{2i^T&9Ne| z`zzXknH%TQ9}cd*1-~e&l1R4)!LqvD$_@ts z1yLv|Ivh!(3R?X`%GMjfM3Z`i4<~um2hr7JEPpp5y_&P4_k7dhGn3q&C;s#FuRW^K za@&)tSW=Lxl0r#Ke6W*@xOY$d(Aqtqd_kkfrlyKA-5)?R^(HM`=sr<9Ug@QP;0M?d z`^RLCQ(;@=L`S9GX{q-pQZQY~T1Kr(Xpd}MGj1q?DmPw~7ci>$m|FIwV!eH1lUq0K z_TUn1Qmt753lTS>BxnR71)(BpR&v&o}#hi%H;gh%=d3 zoE2wE@XK`+5f_|SVuvv$jqJ$sT4rmSBt zP+MPqHfEdAFRL*uN)s$ns_{os_U!@UE1pqnrc@h1Mi)#)dEhrN@|aw5O$fSYQ3lfm z#FogDSE#(Ljx^4?OKRnqJ03?Utn5d>w_+@T9VZL+E6u%0nj(&qg@`Qnn``Av+_R?B z=oQcG`Ix-kx+2xkQZad2(4F%e??Z0KOZS+GB=>LXeF6pJxE?n0hjAWRcD8T3F-X+S zUJ($fYwsd?nc9qv(^Py)!&drPs5ZWlx9$2Fy0njpW(`bF~tXMHbG)u+A_nz zxKVdF*oTaTtcl~0Be|VEW4{PPV1v;IdQstDP3#yFly}rw-puY=TJ$Bp=_>;Tm5amB&?4`9jCLM1GX-QPwA#|Ob zJ1W^aXZ1ffyg$$28GDu%ciRO!8(tkk?!K_OxR=^AM5`PxhqO2OgvLFUK${-PI};eK zG!i^PA@K7yw{9-T+)0$v8!Gzc8*pgTu0)o>N8BFoC{^D`;sZ5?#14^1%ys=@y6Iv5 z!fVo<*W*dJn-2@&le!;m$!)HK3y#;$I*MVv-L!%dgS|Cjh>Q(phd zDCNm_2h=3b*R0K86kNg;KF5Y+pLAG=cC)vHwxu`>KZ2~V0-_pkkH0=}tzT4qE-7fUY(?*f#%o!;9$3z+e6l;Y9l@o3N@sd) zSRI9<+fG~!PrgCM@V2^Ysu-Bzl5sxEM7qnKl!NG85{;{k+^&W(CC*aM4uPae)Tf|5 z{?eD>xk=c@!W_xgAz8E!a9z#ypQYpX>Uih4S&7CB<}5XZ`!U3=;%;#Cv$55JsEH(6 zLShLuIMSruSb{?z|D@rPvtfvAf@ek5dv54M{gtfR*aEXuGL!;H(>QA8b~WPqzB$@^ z>|k$bwAvPG#XxZ&Z#x-Y!5rw)4oum*K-A5r2dz7-HX>q9A31z6oFP#?b;ac8FP{G@ zF!a|{tzXLxP^r4GRFT?CiZmpQzeTDZQxI8*E*7!^#+A_8t*Y2f{z<*1vAdYBKI&KY zRIZ#&nYQRlMbhD32-Z}tZmUe!Lv6aP%Vr;&a%Q%JFv8{tFv&ZgdeXEu7+C2ys!D!v zX|TgbC##2T0oB08+3DGEt9i_>%YGLZzj1Jq@G~*% zju2Bh;-ek-km>ZPra3ju+jldLX$5p2vIJ3D-tE zXL3SJX*(4u70y|9_gwZOP-u$;r;Y!7_aS>vnFBUW8q@&Lo#qj|nk#){)pA$98bg60 zF*{m@grd6&G#Y*~MvzO>Dn&0fUIf_XjNXEDwR$>we5Mpi%Q}dOtC2zY)#fe==#|Sq zXGi9(_D#3Nsg=Qx@iv>xHK}d6TRJ$kU*~%fGm7-O29i=&lVokJ5}v&<~pmkj*t z{Y0j&6Lm`zrTWheBqSjupVW?Ej(xDQu<6(HkV;kySjmzqBdBs%>h`LbLz!6HK} zzd|m@QB|MM__N&+HS9E?iM_6aze>;9cytkhPId2F9MN;em;>D+wSfR zUQKyd%FhQGe^p8U{nF|B?TZF2*Q29%oezMtbO!<=EIe$rg3Ddj-nc<0+}Jubr*d>v zY$bg`{rLJ{TZi>&(O7X?zMMQbXo8L-&s?V3DpQO77Tt`z4gX#k)GpQRKl{k+iCf36 zeN%TlDS3-G7apxskv%4l3Ji$0&jk{<)si+EwGmOmYZALuL+Jo70J477-LI_I7n6iQ` zo|`1234WYk+HB;`+NGdL7v`AlHze6d(rA4%>8MGqjaIjsH&4!IMiwwPPFz8tga4OW z+rpR0M1N(%2hmdTB|*Y7^--M;w%rESQ?u_1KU}Mj-*k@2SEA(hG4EPe`Je_T78Gg- zrUoFuER5Rfh@enl79NY9`)BBQE(aSRTI?>X7Z8yvS-)ZbGCv=KT_g@-?&muRFeZo z)93bj$`}0bRFs+Im-KsVzx*mroFU6O8=8%CeovVvO5co}qn%qY^t$Sv-;Xs#tm|8b zD}Mx&E7BM&LwpF##U2^e!`f+?f%4Vdj0GW)n{6BvQ+=sMa6k*V6U1hHTNYwGxMMT3 zrRfxe{oW{+V+I1ySG4fwS2E^Nw3(kzth_&#=LgIH;*==M3=^qLzn|=YZG_Q+pp}{I z`{zu}ww~Ub5c}ItusZmBhH%(gns6L&14^t5Uddv9=Vd~S)$B?2IW|rS=uC=6Pu11? z1_BzpsUGsxg6LA^8_r}Kx_FAAzuQ2bbQm2UkMLg91p$kD%6)H6y0;Fi6B&+F7A~SA zIApNBm5a2QgK9N2kpJ{$j>Dtg9Aq|-)7w>v$#0M}7_pg^W)vdXG=}!Dh-x1sv~Hlz z!q0jJY3Q16U@i86bvCOo|+yc>6e^t4=bL($j$Pe>uyj)`NCKKN)~?Y z>?1rXRy&PKcSy&LZr%GWDmFW%26yYlqv|s@JC!!~4)D!!MO%d)_hpzVtsnd1iwod$ z4t{g8;cDLH>)!6O-YM}6@I<6ZQr$Ih3))-*O#M#v4n#1g3G4@TrMsprcLNm3o251m%z9k$NNp@wpLb6uLVfrl!%2_+y^Ps8mfgciW7dow6 zr)j;*(tFoo1{+6!2f#UCc@ayJexK&feWVP^(qzO_^BP!5L0!V^O@> zv^JUB$BFi65sgrsa|ia_H7RBlt4*-ppGoqrbvRPUPSc_07VvpID;0br1%#y6+toQ+ zbX&o#RS%vaTl9z>gYE4jD4WnD|LI!>-WyJAK>a^+ZrvP;;;2`j^rm zAY_mukv7@L+!si<>U9Bj!M9E^k&(PGo62k9MI3e=rRR?rDVh*E<_WW)nuwf>%z9u9 zHocMdzc0$7$pM8yO=MiqC~fokA{OrfA;up^#j?c#8=X>(Nzz+Ng95cdZQIi~I1yU|&3zc-CetPz6XECN%hJ5N%9c3|$W+O2b^wWCm!kX57XBcy0gfr~P`*y2Yh@&G@Ng z1IfB-^H&vmcE{X_UAo+~35AoXl7Dg(sWvSwL zDLp1Nat|7&Us+MKHn$Pm#@y8LdW8fenADj1_}5_EXq{Yzw?^pw9A=bJjYJ-k z9v09DA>s4DKg9ZCI(YOuPt!6I1;|C!TJ-yJJI||I*3;;bb22IEy|S>6soO%T?rft< z3hqQgR*~^?1msF`>R}k5iBEJm2lam&`D{?muW%;Qj7yCQVcKq6DL_vzKXPt9(@^e+-dnjwfs={po@$gK-;ZNIi&_H?i%uI~Tpr>r$o|NcMFPlJw_RyPrJ% zgu}Z8{OGj}C9beW9bHP%q@bGR|52kEs3PB76Q`TDNw)!>C4I}ek;g9GBvU;LIn5`q zD0l4l=~NssBKj+GIAE0Q~-1NFc;0mTm8zq+A+0x5edU%Jqv<++x<`G!5>)qD^f zR$-2?V5@y>vp|U=OjpW|8xH>IBWWzk^wZDfPaFrg)VcKwmD{T4Ic8KM4HJA<#mM2g zX%6xj69OUa7bY26b8mqS<%ictd z?}Oz$IL~ni3I!Xxn?S&p=@&5nszx1ZYsIR7B(rkpDwu+DZ@c-&(Z=V2Y67vkT;^*`yc_I|8`W-e3A6ZdX+-qvn$VDr zQaHIqAKaFQ^5GS^MJz*e6ZOnoQn3I@N$xi}?$3nKM2`@@@W=Qz9V>89F|p0pWF*=i zBWo$fWcA-|pZDq7kudi~Uds)7+Af%>QN9zMai1dqR>lC?q&Tn_)a)K zx9fw{gE2Zg(E-nMa&qAIgY2YpIo@*v`C=WK!dcvL)9CvL1FFAU+BAX&F_%^gblX{e;}XMh)y+C^;H7pHIa{XHkw^ zEDlFJbJYM!#N}m3ncE_6?-DwR1IpUR8y*eY!Nx5IacT+WYX)bcM$2}5QMU32vy~Dg z6T;(Dw&(wuhij29jwsx@7Jb;^`_m!q^tVnRd5>ACMOB^(g5Iw z9VH1UisHwgTb~l3b)w)8ZPYox@{Lf@k=oNifA*vlFnnyG6#&_#bAD3NCgA^s+{bObW%t4nb*6YB@;W3`isD%)@;HdAFVw4BKg^MI3d@>-tk|fNLbZgi9 zf4rgP9-WvpHVg|Q z#Z>~s0WzVcIPTaE?gBaj|Z7RKm~u+&1m^RUdXc+y#n!BhkFQ!->AsvF*9lA=$aA*LjQ$tA(Zcd7~<6 z@xjcxI!JU-1&bsI62oScN#N<7PSB?)Ie(BYX3#do9NYzlyD=aklJ9L7hQBac%S3uf z%-0Kk>I>I!NZZ^Hq6mSULG+&ns$vD)-Y0!Cn-wRN?mR!4hX;N=^@xn5*v18kTZ^c# zHKDB^GI%|+^#P$(7qAJ~y>)Nw#86W~L}CJ)IaeBZtIpuoY6MOuGMgBW7NgFsfqt6g zo#W)vvm{cs7w#**PqrDZ2|){_qX(5>9$0_5+@jR|5ql`H7F5$dz;kd^6OYJUS@v7h zjO=94KlsI`agnyhm%4PdokAZlM20Tgz-{`heR}!nAhsuogQs4jUOw?F{aQTD z3rFSE&>5Wnl1gU%tE{o`&j92i}GK&P|HL4{Hr8R6z>HywqoIS-?J)8ig!y)N|NS4@F(@==w9 zmqS~+4Q!XVwj|$Soj4FLS*3~BdtLBf&y=KwE%@Q)Xoir6ve*2kY18Nfyq`j_bNUBw zj*XiyR~xVF`He=Nj-AjWw?^&yEac&7iTeaoy1DAu?#XjBT5^1^MJ3BW0kw8!!_-Gk znoW8?*48A$(T9M;h>zi(#N)(cISM(e4zKGA#x0!6<3zJ*a&yQ6rTPm0J2sPEyi6DC zRjHZyiim5UcnKuTDn}+)Ysm~p$z~;b65k!p1!0rRr0%xvZc?n|zoRUP=BbvMLeDJv zR8d1!v@ktPsmsmet=_P9%}tQA9HQ-@D9O?$#40wN5Cbf~mSA@xMA{BKqF3re;oFo( zf#8T$N7zB5H^q%2!yKx;(L*jflo@TruUYa>ZQkeo4GY}~=av&n#%@q-OF~zosWC0J zqg1TN3ojsvQlSeY;>o&LFA^V+=MKi&2MwMW28M-Y8EQ5bX8x>IyOJ7H4Q7J~ppzo8 zJk_=|cob{}nT8DadmQz46N$kFb>I)Y!|NF4OC`(QCW6#Mu+<9>5eD}Yn^LEwX)$X= z=(#1#gvZ@0rNs1f2qljrT6ubs{J!Aoq}8>6wNH~UV`{{zYE zjJex89L-glR($eP86FVlwS^Y;Q8!Rab8%Dpl~AnH{6OuLQg_wWJLIdYlgt<&3LNv@ z*^ce$kV^JS;{Fho zd55}t0!2oN+>zu7jfCy5i>Qx*;);zH)7i!-&(%n}^2`82V-rvGzd37TPJz!QXKsI5 zcT3fq03MswMbnEP7VwbV#kdy8k}* zzP;6e(aNmzr@B{p+~Wz`VqI`CLYNSsev_hRG+k+tx{cV^v(*F6paKwV3s~AuO;po0 z%VTA(=lTY;Lum7W=G-umBzldt9QuDD_7ftv9D|D(YEq;u*@0}d9oe~}j@cFt6)4Vc zr57%IF#?xWeljsxAgUoQmQA;y^Hb25Ie33}WR`j<3nFfMmVcGa(7 zjOi2dhs!8tR79Gff9e_pWML=?`1)>LRotN+4H(9Q@a32XLVs$Ogiro~hL%paa{MgO(xQn2(L@x$x0pee|s7vOU{NflB z(eNMx?A1id7D@L~lvHt=uhkWq@p5NrXmc=HWz;*K&bSwFD!L^myHKBIvh0c3iZ&fe7 zRDQ`d!SXj1J);+a{_e*)_dH1_8Karop*9b*N)K<2F7XH7UoF-7O0Cuh99T?)=bi83 zW88cQ!U`OLV@=%it|w33y4aEa6VpXMHCD?2IuMFQ1^yf1l#KIKj#PdFtcBR(eC-^_ zs%ShlW(_G4N*2matc>J>=>G#*G-Xc*5UrbyM95@7E~a?DZ;s%4d4>#Kac}wb3=4!} z`%tL^*0w?W#jSj-Uj!{G?%{haAxqeg2+1O&%1BD=aqBNj$n}{d9gE=;KXYc?Xy%L~ zqp8AohY+iSjuujCXU^v>h)YVPEJHZK*9J@5&=vE?zsmRS8IxxNtk6%j0ZJLS4y1F* z@w0y_$j4vgsElUQN^UWi71G6-OC_^6ZgK?k)F(eLx>J{h=KndZ({YidhoP0M2{mU} zCNNYq_Su=T!$*a&s8X<|SS46c3OyMVu5`|~4mQYyWd$E1)b!vP;V`*UDCIn$-k?Lc7cFE5)g z8_%)?Myhmq3e{t>h_BM5im{&ap?>cekS5xqMJe6RoA@sIsUdx)>P8!KC|i$dIqmJ^ z3^vMjv&RP5&1ixJwvr6R{T-IRV}PpM6=l&onUbZsbx!zS5GpF$!$zcCW=AFVF_}y- zbN}BOKi{$n87zri>4f$&l2v#6a*3BV%sPp_Q6QsPic zR^}IT9fY~1Z}-!h2F0|S^~TEJAS0e`3-o_lU1zHIF|bXYRCb{wMlX08Z51|De^0ba zcdF!kC8b-@V|gfDazs9L60DasKh+Vhs5|{O)?U@M_;CtL0lr@yAKt$h12Bx%A95~ z$Uw`+5TT72#&&7VSxxmk_*9IKVNI0E0T~8{)5oMxn}4m>WuTJ~Dy2~{mT)#!@(PTj zI2h$?<6pJ_x<1CIm4r`Hs?@Qcoa>}DH!ah&1!&4+k$6-XH8+=7=jG6p0sj$IuQ*&2 zfOTOesx@!4-!_DvZs$}gxI0W3Q{=VTYHrPgOkE!&gMcDqt+Y0vMIg!3Uk9<>n6vd* zQx_);%6VEzog7@&8x>1qg`3TCt!6rfO?8n{)weP0&n)c#UOYN-{{+)>wtEcS)KBu> z6W+`qTtFDN?xqRR(3?q?3NPnKN}E#uJCbd2?A8oa`1E`AsWA9rZQGKt_N(n|*P8>O z!h&&E8uejDB&lYHh+>#tDq0&r=j^CU1?1+H`@jc9#si1trrfQ%>I6lmN`d^+%cH{! zV^1FGp5xb_aHW_yB2eeA_;l z7os@fQbl@9lmW{1HgVS)$&<)J9&qR!Y%t}s6}eJya&eOzAKrPKgtW>1DpaMU_Q{K5nJJgk@4E}|a^I1o=9c-AjLG~P8Xx?`jL8r^dndLP&;e!dj@tn% zTOBR{X(~&(EH2W!kT|7~3KpvG-YJh<*~9i*kiO+orz{tU9qnHgVsc|d(L<9pR+`$_o`2{*!}l0SFJtm$uKg{J-0A;kS@-Pp=pjQ zDX$i$nrVqfgec3v6odFF)>}vp&>5!2sGiMSGx?Xjm+uTexz(O;ZcdMB;&{;?JNMa9 zxx|Q&CHO;p^R45XU6|DQkl7!?41zj}PF}CKA}6_IylU;Vb4|zKVx6OmfM@#G@Dt`M z$kKFqLos2YSP*IXOf;mr0i*+d>X%yj0SNM1f?4wD>zb;UO)z4ad0&bMT+N8Ohl~5| zXQ^6pEjz~}jBoU6i+O5So9^rp(KQVH8XaaD)|wQ)=W5S|37aC%M7O;&jkT)?zGa4H zigRM07(LNp#Ymu0Aee*vgwmJPY>Oj#O^{^?i#BR{dqS!FjZ@(<8SC?Wl*HY_Iiiy} zTZh9-3{Ff@@)kC?hdJtnYcyD0aXSde?7kb^CXgPz+Bfp2WTcY4?9{cMj!r5&h%5}^ zAagTYcI>K5*@FK0iDZ2cp9Z#BK&kn2BN7-@E?t`{;Wz_$@-kZoFC+jl=7y5UhR;4e z!KvMNlykEt$!({BskC6|=vRR3xS1&%!Pb)+z)R$0w&1!HHnZhSUhKh|6KnOTh-oo(v%BU4Hp_t4B1b z(>#qK#mqV%?$sV=bxN4#g@;p_>+JosN$s%_J>}*!S#wlqto1#K9cPZr+pzhfuI*^3 z#CBq6gqw;^uGXkjy=>wP{^}}+{rTLomSFyUyC#y1OEzRw;5jf0msgg)lMS-2U`IBQ z?x*VP!O2kbh_$WpB!IdT$Sq0X5gX8&@pHQTgeFw7qXW2RT)A;$jjDLgBv~}0OWwu? zbellxmfK+Ur2+uW%vB|j*fd`*xTa~}LQq|^h7BzZ6m1U=88+FDNE7gkNY(qPI5 z`z^isB2`Cx+Ysdk=It077x*I`2u?&JTQV@VfQvDYhKOPse~R+$c+#2*I^6LP>9lI* zHEuNA}c_52(RS>DPBxjqS!MI6n38$2=C@cC|=v`=0wfQ z3DHeswA4r%LjjEiaL3*?YzmJTmHA7#W2P!Xwu5F0L9h+lfo3w*{RYicG*LPTd`0G@ zuVADu5o|iC$55Vff|K|w`yocw#p9?AllX{+6>oo|Oag1ruAle{rk$;Z`2^T;m{4Sr zI?;~r0FOl%Q8Df@w84`A9>n@LUFX&yUr@c=Xu9UeH^?P@jTPK0T`{y#p1=NEs$P~` zL|Bg`gIe^b>?0&V4D(jk*&NL{hpvDe_7WVFOTJot``gpnD|h5nA@J_J&p zxdY7Sm3L?gc$1dd32=XA8QjbUn~ci-gw=2jD1ER8atJ7iNR@U$(G*eTDkfK+^8HQI zBnowYW-@8X`5tEvxqms{LX4x0pJ%@cEz-H8iS2l@LVBni>-eX? zk$VBL1T$NBTLc`jUM!guSoE;|xBBdX1j?Ys-2zLuCVv7P5p6nvStgsW8A(W+qjL$rVw9k|t z+WLJo+(X@e1Cnase4;`S7`6l;!~t6=#%?Ol&N8JY<=?V>@-`A7ms^R&#xK5+r>1I$ ztpW|OuEHej8JW5ty7Toi$p;4`=;aRYo1ddmt+%S`RUO-AIH5|(T}Vw!;R(O0_bL+a zxDaJ(3XK>mqR`x1J z;Js2vm4$mE_DkVTWir3-!N{@$cAf?^%EMMQ_LD42O!%bJ12D9X7IK)0P~h`5H#xr} zJ_P8UKyB0pdok{nQT2M-%@np$So7uhNTDPK9nz8`?a>9;FA&+Rg?ooq{v<_M)|lG3 z%L(E-WSZZj*x0Mn0fE(_5F6AeZ0JD!c+Be*x=AvmqG9x62>Mlw<5-3VvNMbw9a>eV zzp??iSJg?F{l4t>`gJ7|=k9l-x)eZ%7*%5@TNB<36*f<#fK0Yu)R=*D`o zTFbtSKvYnT*0c)&bN#t2xaC}stWSiC*e;mu=Xm9K>;{4!T*)ptBo^haNp!{wPZY;WI+JC`4xf?~GAgVMlkhFKZ$x;_t=5_2ujh z)I``9(S^y*kzfzR?o|`3`p&p_jR7Z|`40kVN(P?D3Rprnn+59fAt&n0plZw#5SJ&A zhX{s_iJHZPj#ig8)F)w-_OoO=M$%y7G$UmurSbCnam!jq_(hQL=H0=1`1_>lU8%V) z1F6P&IfgR#LZl-=O7*@3yS`a?v$^*6YZeUw@8#y$Z{U zJ5202*?ds*Wl62ukrbPwhGIO>3Xr{7QAD_S^=xmiAx_mL%Q+M=!pu;Qb(xHRv}M7+ zxrwCGH6&zao1^9}t`dz<(2O<8Clu{`P3p-Mo95pGj^Z!F)&VKM%=%Pm7CB`SSPiK0 zPYqiLS8}Wt>*)=u-j8^%^K5XS+mZMvq7AdycwI1#3||NZ<~p8jLa>k}1Ku6|mn4ac znij2V3x{L_&_`fe!!?fOJ^E&dou8gemNmmSbFJdT|4b}@Dda=K=$TIOiG`1qszNaI z-nr~sLo$b21s-g#LX7ql!zX+bz9J_0I^mFh3*NQJeaVu3_f5=hK$w;m!cWMW|GdvL zL_ZhDz5lJi3WVvg5rb1ujoEN=5Gv`mqL0hT%d>7yXW_c^KW^|&V`AHIS3whJFoXF? za795CTP}bLfkr!>3_p#MSXH!VX0VqCVB9;Oq0TY2ghm3 zgv|e@|HY!+o> zcWyvg_{YJjtb{Q9rdnBB!RW&V*=5%vuusvPvo`{2Yy@lMxn$Bez*}-F?~T4HQ7ZCw z)--aYo7twRnqRSZwn$b^`OihsDPBipPG>>qK#=e__B6GP-|y>ZBE3L6RF-waE3e&D z40k);EfK^u47;oO$%Y5QR70AOEufHA$sREsi3kxF1);yR5$RyW_!o4h@B8orWkpi!3*6`f5)uz;d;L8b3?du;p6Z^Ti` z)G;VH)yIo(Q#1};cHWRF!r?i7r|yFAUH_S$*@#wC^h~d#unpQEq2^-oxrc+4>fES+ zy?dSe`0d2V2k1LxEvPE}-ai>tqbM(z61-Mxv4P@6{#5wP(mw1C5;HeIPMN>xkoMT7 zaS2=Zlmr6>@i~rrBM|~2=xG1NFa~1yAPR#V0nN?z!j zVHeGbL*FOhL|T-TGPzfqr33@p;X1z{aPvc+(@HXOQ9VMS{qG@O$3I9NkK_n_qF;$V1Rx2Q2qB6C>b+^i9bxkbLMU3=apX;Q_G5#n zl++$yLCvoe214oLZLupJLIV9VyCe89#K9PVuhCzN?-!`kPT|8SP3KW@STaz=e)iXI z9%}2uEua~_l?NiA@&%8QTT^kxRqC?a)TojO9*2-O5*5DLG>GoCh>5?0Wy3#zx3iQ1 zv&n%7DKUL>jOttvQp5VEH*5N*=C*;wh0~Eg4^8kX2>97)ss_u2OH;M8#}lMZpX0i|>Jhi`(IIBJ0xl+aciu9exi@ zPMd15@f7vD9x!&_X}H{IN8y!>>aUE8UfO&LZgBxIi-(CY++Y;g$!EMc67nxSsWV3Q zzY~+)9SbG5^ZZ-G3UJOry&ClGKp2g(0VYr; z8<Zqm|?(=2~OyZ&=&CWk8$$+F{_BDru7s*L0~D zTP1b7(X`@?gi8{ent;{f%!0dHT%y~%(44&J&}r!~{fwL)_tMT}j*6SMLmAjESGwqh z0e#kuPdWo(ADLn*--VfI7MJ+78Vc+Hp0NaQi@+rTGQrxs+^^Rc1hfmMJb_#>nVc5- zL^VVwwN}|(q`OHk`}sw?-@DR<mD%$8DfvN zKJx?h@Hb1}Z$H}*563^t`sg4L|GpCDtovWcA{wH}Ruc%6dqOroh&sfgjND}oIr4(4 zL;QKB46`KwrjA9bV#@2V|GUghX@Zz>=nYxOqf0oZ8z_&@4rEf>M-lk6*(CVBwFz59{M9r)xu(;fN~>0X7ne9!YHXuS3Xy7YAWNe;DoT=Yf_!;Gz%2@F9(54}WFp?iSo zK7cPG64>A72h#HC=M7#7q9elBK?U6~9Dmg1MIfF!6UbMQE_yu&kbQ}mmub$`;kG05 zkZaV~(1zeAOJRH9o~2u}hLMzI&B`wnSrZ5m3nl+NnGYEKiOv1D1|xccA7pO?w=wzK+g@etRZf7a7#NAMm0ZR)=T z41DTpgI{|F{M`F9{PEIAiRS-if=#i=w!pEf7oC_wU}4yr{I|R7D>{PW#LGI_;Rv4k zlZcp)d6ULM^0*3uxjFJ-!LtR}S>UWAXy?V`tNUpXk&ys)I-9Xy4ax!&$x{Tsdb<`%r}Bl@`##*AxOh9VpChXc6aq|X z#kXvl;tMAw)>0=O0LLZt`&0=?=o>fmCS0)py--LDywlc zreq;D!#MHF@VS>1m$wHA5uYB0Zkp#(rk9g%HX?BdHBG7>#US7-DM!yny z!OU=b&`o2+R2;F}W3ktZ?ml3KDaWa?4}LGtZx8lj9G9kSQvaE@Gy;E1YdmmXCCDG} zh0>gob_bH*IYi_+_lYd^GzUc&?hu}Hk=X&~_ngu|yIX5Fj2}@7;dy4dY6Mk{EYwqkG1Dx|) zJ=AOloz__vQ1C^4t>J8%_k(_Hl=pO@Jm8rCHre|2c!za^%>wn(hLAo{LIu=D*fObX zY<3DE=ybPi5^EzXS_~=tZTK5N_uEJyZN-E9$4fFu~{b=&;j=RuPcnNX8 zPorgM^0S}DW)Lvv!B5VD1d5M6~e( z40g|+a#S@v5rD%T-Al~KQ&Noj)(`=ih_8|C@6IDDgZFY8|GSBP!c7LOL)Pn@V>9n+Q`XxdS@Q z;2xBSE-YP6$h!&wjG>+diG-z%fj_L#Ypm!odvTISypN{M5wsOy+I>`nsR*4uh;ZU1 z@$hZnN)19lA?8n>wnLAF4Fb)4+cU%M*rz8iyvkqDEi65(O&l=;=bqanq)gtw~EtbxQnxt1fhU8@+ zJd>*#`uZrTB}%U^(?FMn&qN)kJws@hEmOKwCA%3R`|;Oif{jK5#D#Wx=$zjiMAvN0 zZuX)`MZfX2y|>JcGZ)UD<0dr(Yptu^Qpk1chcY-1YE0P-6CSRmQp+rdC%x8AQ08$Y za!=_e>FD0%_6!tyIgJ){f=y&^N+4uw-M(&)yU~wm;%p&5bQ(4D){6cj$J4}&)5;$r zPI!KbD$KD`T`u&fRn)-lPBGQWjYLiSx=zd8g?8>;_}Dg?#5T(00Eu(HA-~TX>4Zln zVlmya9!SjYLqY#ytAJok6N)A=aOO3q3I)_o7AxDwIDGb#LnJTGR!@qvU9LvMlyc`Q(-e$DoEG}G^blN{l4L)fti#>Gy|hHCD#|E4LH z+J;>BEPWR`kG*^?I|yx?nD$h2a@c94&&<8XG1}X(+U#$I)xpN>XbZH)?r6j9Y|~-H z48rhU6j^no&pOk?vN#Yx2G8P{A3kw~WpONsypF$-LLM5vsXFVT-`{*RWr#LmX){K! z1>@|nETQsXm3ip@#7-GD!;tRA>rO93eYGa_DKjvXA*T zNJc%9G~Bhw<%Q?V#NVPtdUm~^d3rj2xaoA!4WdKR&J2|YW#7JSuMvdbDK9G5dl*va z3X|mXki%St{sn=TKdPB1eR{_2O=e-cD2?Dqh&Aiba5HLo0T^uVh1$5B|GIqHtsovE zpOLV`l`<{YA}OUKsf5aoaMYE$h>V~BP@@vD>y z7e`RK2B_$m*BOr){~Cf;&1r{WiqF`gNH#WfQA?}qL@haaCS^k}bI#AK!>jY>=jQiy zb-llBs{cGaj7(uOo9q;7lLmJS31e@eg1Ltd=o&hxV{D=Jq)9Sf-U$+Hk|}$PAqoJ` zGA0OaW>(iPcDCms>yZaz!k8z`0LyS@Q&CoHJA&YH1A6hvT6kfnb))Z6K|!LDT75E1 zS{R1>L7>9>W0csyyzV^lIxFrKHV%pt;N9(nYwu*wVFUoY${AvOmk`+P<@)`-+&VS} zE3;*WozW2(Neqn4&fo})?9P#|Jd-YSRLfRF<=TI$Se?trDOPKrUYGa+Y+FQqU(q%Fgo1vS~54Q>!3N-{MW;N>RV zixu#&L_*1Oz`03QReK0$5x6Udb4;JM9qLd6)1S6!z zPGIR~pe`}5CfhL*7%b+v-rF(B7O##mCc8h`>;Nz_Y2N3&P0XE5=;B8oQ=0v2 zmozeL63&z@u;7MFeSTPhLCq@PPTaw`1|cTBJ&h2Z90)Efe7eff0-(E%{~rD0E^r(S zOxu^(7@2~g^K9XQpbg7lsQm(*;FIfZqQJ*E6sHA1uMsK$G8f>KfJI6MWM@F#m9P+r zCW_h)46Fe1sL@Unb#|U$fr4K>6#7n}H_UtQrOO@H6PDLk?{)Ui2R95&<1duVEKYIF zrPFEoMpz^5M))q#1MrL5%%DYZdIoTg@f+(9XY7mBl>>9ekM(J-g}bbtLIbjr5?DV zDRgcsh$rF<6so4&In|xMv#W;PpmQ2 z?KB$y7yT;1$y}SNVdceEuaZoRO_ycm)Kzq^a&k_2pJ)}Vkqvnl@s|S0vr4}Gr6|`K zjv@qe6pjtOuf|T*c_$3q#3o>C7Ixdt)U9G{XB$XNfpi+z+CV6F3Qego{UY6vNu~VJ zg`m?CJd!eD)=gTn@LrLB!U8?>tg)m}JSo^MIRK9E!-t~sv^dQjh+ZKhW>LQjaH15O zHe{UD5J|S3W|3|LWP-k1f(}p0ew9m&ty4)ekgLT~;UBKI{%?Vk zDAKv95@NI>dBb2UWo%D7DWXf6Z1W0+m%=8P#jGbhHaw(?gB3W|ZuQ(yq~E2AAlsEx z##3o*LT1(VKx+>m0tE;x6Pq_Q14%2U?5(1h)2i=N|+~#+Xph3 zH}cJeGzQYs8vo9}!$RZ_N4MR-%fA1galAU1{SGJR2HbWph2c_YD)?hU18}yX41Aq} zQenT4FIaP>HAbMu)*9GhZ#OQm^+Pf2i$D$D=!8Jco{vj0_uqt}@*-H{{UJIv_u@Pb z8Q=_Dq#O`Hy?j@uFIg63V9x9j6SyR`bA~UR1W~j0dj{O!4(FR-e&dHEF#pkke8)R; z8;f7jGzIu|HoU}Q-QOuKJoKQ|l!eiG{k@AeF*3)Awo=F6)fEgcU=^D3{_WsmMs8ik zkHKAPDkpXvwJg|!Sg9@)Cs7)4vyX6SxD-X%>=a~O$V^Di6DRxS(uzu(2d~j-QXn4{ zaohu-QO&w^ePRE*xW+&%&Z>*1BcUreD0Mzo6^C+gfdiRmIrT20wn0#2g>@URdBR6% zT(M6FYp=}Hg^8%8Y>HIYV_38fiZ8Kj`1A5UJwg^a`Z{;*CjLT!(ksl4(N$bTG|3Dm zAc2yXP+jKIi{THWHj8Cg12%IjF)*$8k=&7_4AX>K*jo^TcCDq0wmZu%C0VK~1lx40 z*-{Uc8jqQ_CFMMLOJ3j*q?dVk#61|K-Yy6k<8PDt4mX^2H*ROzw37%LjJ*9oRu2vE zk|E3U_&XM{v9Tbxd0B}@1;ci~Nw%aJfz`8QXvB)5wvd;R=^gc>R+vsz8DmVx=Dwu@ zh%+h8l{Py#Kczyh)BQday(9lO=;_B<0?gim4e!>Zl(C}aHbK~+7ah-SVLEhq+EpJw zQX}R8!Kx4MjhFO_D_c$=cKmWApo0)deh@tM@Ml$83<{! zAuI{P|3RWleerp|l1+@S5S7$#M>?9CSu^HQ3HiSB%lnM3_xe6L-p-GpX^4G%KCkQT z{l4B;FZK1mygUc{INlDXvWf<26BIEz-4BGIf)UI%h#=KB?m)g@EHRrEPWXzdw8I0v z*@)bs@n|Eo6k^0F9Cz7zdr=%|nO~#Cpy#|yPq4Bj9J*nqKJ1V4PuhPfVBI^OW6d(EYni^3%Ze9~I&;u`s}^Uzx5dH^i0amx(!AQ5 zhG*Wsq6*zWQ9jzHV8)c4yAZ&T$F{^&Qi2f(WE)}09hR!fPC2D#>}j6$@(Pj$8qDd! zB%yII#F&H2umzh~bY?l8h8ZYnC0Yv3aWD%gwdYaMk&2`ilB&>}t&YRKYzKIA znlMn|JD$INk>Eu9ZEvDYmaD-jP`TQy#Uf%vC&!}}wes52d{&H)tkburZNl7>GM*8e zkkvTgsjNi@`Vz8{hV3u#`@0#_Xb@SuvPZ~-_ATGlZaG7o)G1TCSp13vi z=UFnO#qA+kH!Bz*ZeveEM_DC84;5i%tVThTt-Qox{_+?|a@kJhAk-NJ@~R9%V;3%yz)-+1FkQS70*1Cnzv8ipFY(M-XPE9y6G z5cX9Zt8QPt{kgo~9@)GE42Hq@b^5|6;k|-WMVhQw>jl;on+?v^{uu!St+?y)CNxxgMaXV#N7!A`VgHG&E?YIN zCq3oY@9}whem|&=R=<5Q;sMcBj4yS`TK+KjimQ{#N{}==f=aE)?Q8^eU?*IGpwrFH zs)NS0vMt9>DUTa;f%ymVI0n}OPqoA-1{(`iE{f}WD^i(7p){tU>b3l@LAC%YLJSF^2{iLNw>|z5{dGAFwUr86`R^In8IRthZ3Y21&XjEo| zJ_l?Uk#t!lqBi+SS4IoqVUq?-!X_1~c%7QSIv5@6{8&`lU0n-vH-GCV$kqK?id$L(7GlyBCO(?z~TQ42fX;qf+!PjgTrv`ghSG75d5Ug~>lrEg^{zy+w%Mu)a0AKa4R(z#t7e=hS0D$Y zVl)zD%{+x|1E}kLL<7nWDwwuXVWg(u8!Q`))(Oodggl~BHe8lC1+usHPy|XYh?*!6 zZ&hUmbrDM{R{2w8^iK1eVpfp*6q*N-hnf*54G5U7iX(|sB*gOBV<x;kI`cbXTNI_EsPL5y7!!c=^(WmhbPI|T2PLxX>s((g^&Ubb7=|bmPLcltmr(5EUvcsMUnib z#--Cpje1+Y9~$u)cFy|#dL|p}P4P(5i4GQv!TO&u3OPY09ZL!^oi)6{?3M}?&L(kp zsS)3&)n?!%Mz3oZ(knjO_^rMijKD$UC!#|x%UBkjs@l1uxX|%*;J#d4C*NI_d=$f?M32dF{G)Wo?m=E-}U~73O=*mF2 za?hS0KF#q>zgj8KtciNv;JdY9-&P!F zLHt`w~R0exKF8LiX9^5p=E+k0SDk( zo`z4#m`<}GR0kX#t)d1V=cNQ88y7DZFV~i`C=Qj}2Y8XWCb4RC5Jlf?@>``VN<54m zwnYgmhWKHrc2;aHE&@qJTI&cn(4O!(ahleMhwuH#LL?(jZXEaMj&YNLa5dqY(&Eaf zp>;g5JnVY(k$(cK0S2*i^axPJUG(SudYN~1rFT*1yxgHHA{K&mdN?YV4ny`4XuIn- zJHy{lNg%|*${!N5O1ST;JrC`Vo!GKHH$!cZSfuZ^D!<_&mY=h)?;GnP_SxX$ zQO>!*#Nd(4_%YuWm*?D5sc2HoHA*#OdtI=R2HZb? z{C7F7-+V*+>$*@OSzKBi|XWi**$lS}6tPmnqD2Sk92hXrAvsEi%>RTBILL+vw zm?aoOnxpaM?&ReN29Ek|D)p+d)l)iNH-TA^o$yd}u z8!*pq#Pm3fY+CiN(lX!CF#n~S?nJwK+uFVDY+rq#qX1ieURZgcABr#8*|`N+jg?wm zD_ykXssfQb%FEp0|JmH-`_eYhH_Hm$6qll#-O2m%dHUi62@iMqXOM3e0SPrI)QvNQ z`gpV2*`yPP+M~4cVXv>d?kJ-n-pZ;R z?o+Jl3Fg1IG}CRDZBs7?w8g3c6c;Ru8IsDo$uAT&1(WoyLc z5trCKRdmx(wT0Dme+SOTv)twj*2%2ECfQmZETlH326EP!djufkQ?TcfLSKj|oJS3^ z^;EQ4lkRj)kZx;+D2*r?Y+B5f@RA`5KQ~Xsib;_Xt-$XAs(3WH>P)6mxqZ~N`H`mXVzepQ2ohCju(zl+-c=~>KPdkc zJGsFg=15~PCNho&6{2~T8#|;YQf54>wr<>DFXJGt*mO`eNy(3VNw1S)hhs!MYp<2W zdDFm3z~V^5p%6z5x$_;jdlsI72X#4Sl`|Zsk-Eg{FEHf=J&Belj`qQ7S0o|MdsjV_ zbPy*jTF!`ygI%uznTdm4Z5rZWR~m21!7taIO~5ZRtb<)?JV1k8Ynp%616*txV_=sW z=GZmHGqw$Jt}O#xD@*^Q_+Q(V-!)mAw~JgWZxPH4f|MWOVj8+ZjRE2-Qpc-RG+>iP?xKGMRi`;)H*1|Tr(iw^(<;0YEf#r;t)jFO!8NAEQnDnz_Lib zh|}OKqCOnV!{JPVIFp}u6lLK8*JkiR7W_AMSSU(!$Uuu3b3ig#<>47;kV zia4jSqDf?EgqJ-f@x~oO@sQ3*%{D}@vIlk67cAuvUOY6^Rb`=*NLy-rz`WmK3rZhA zqwRK!QOlhxj7Kzdfe?YiUi3VlY9NmdGU#$HwE+X@clGC)ZI}thFs(uxJ&?Dx_jJdq7IKEmvU=~Ixo~W_O z*o7MAI=H!~k}7r~6{U{(W6gBU2h1o<9k{Hq(U1Y()i-!%X*GP=r>2?jM$girHGTifo`u6k7(JP#)g-a2dxWD&-MR(NsuHacRY}Zf z#dBqm0>Ok88u=tvsln8{{^x6Up%b$h^%35wY{7{M6D18Vf(I5>j%u1Cu$*Wk%WesA zYDKfCxtS(dyKsP(1;tXPjB`&ili~7-EE)@?CFa7Tm57%$*^i+546$Cyg&2_%XAP8* zfi>SzqDA`@hO86J*%5_;*74G8=??@sW^IMi6!PMxS>0duC<aQ63>8~2zxMFJ zgO0iW{-V!Bsm3FwO5a^ZL9?@!zv4kj=TfEQFlC040R)Y-h!SN?z*rAU_!xa?C#nXC zx%;5Sm4%u97G=VbDgpq%hUeG|7OPLRPLk$kA(^f~te1mSxyCU-*@9&^F z_FEDq(LJ1I^B}?o-N(I8AM|-evQX=}tuXvNef3`F1{!PI0POwoW_7-PzVF+G>qA~& z(ci)NXn9CbA7Bp?LG>7gr1H=F&ekDZbls>;%md7VqR=C| z7LxvtYA@!}N+8uumXOFa&-lY#mc{n+otj{Bju6n95VqM-)jpr5G4Qj9=I-(QcsuvA zG6;!ZVyC$e4bJ927ns-OJL1glUIRKpkvE%6&`HqYrpZ~0H)6?koRj3oF)_MBy`Kt6 zhMo>5(MxS2loNM=yAKCns8pQzhn~*cW)B_=HluwS z&qAk1i8Q9ysXY8K9$$N20MyYNxlySJ(oZL%>fAe!o> zx%!k{p|o7WRnQ2~5Bn^reGj+4$N%iI?dh3&qs@4I9s+>g&J%#%TZ-%evH>2KI5TsM z^u+p*j%<7dMN1lh%Q>1T%Pn0Z_(EwR%~6Y6y)Z5rsz)~yMN6cpxI8qzW9$)jYf=4(Pd<*BU#739T>ZRAFSPXaQ4sMiT)}W`%lq- zB!6G*txs_FpOxpop635M&)@L|Z};t;yT5m0zqxm^`}nwb@~ca?b$GD1``tn9*T(jD z1iOj_XZw?LGjzPMx9pPEvvjF5D z55(?jN4iNDXrw*Tr3neuMcJ%6;4eTUn|wslY$#2_xkVeaz=mtx_BKrIcZ|pE2EyWJ znoMFt`e5iOpToHgu35x%r`cqSbkwg*?L+O?B(M z=~pRr@5ck@G?OAANF%A{&=^Q_!ZJ6VGOf8}*Ftm(usb9Qi>NWOYX5BEd1Eg?Fd(lc z8F2tV(wJ9vA`zK}lxo$@IO;~dPUdJFpTk`s*nPk@e>}IprFj9yMBnAwQ%y~Y@Kgp$ z5SalMuK`tuIS9CF{HQ2Kbul1!fF?#^GN|C z{Llrgbp_i6Hmb_C1UAAX@z9waW9T3@9&Jc?hQSy5eGY}082`4SpHzrlo`c@~RwA&% z)#At{R;wcS$s|?K!l9d3V@xD)kek#L8;@)Lh-h4sJ7V`#7ha;>CUT@;>3!jD#_4i` z0!B!H#@Ay62EB|L)FPu?=HEdT}dn7iWkI1t@7}gC)!auemTqhk+@A1s3D*anQbNM=|Y}{W?YYSR}khXZ7%z_{Jw zi|o|W{URRh_-2GQj4C#+{ZL|*VN_#q7F}+9_=dTHK9zl~Bo=5|P@J0_FtJ98be;M+ z(W-UdLtWUB8};QIs@H8;QIW7jUu;abhK%DB!JL9lp_#P{BQpigJX8bK`A-|T8<}8> z^H1|xbr!?Q=ba9a!<3%|VOOiHs?8*qW=FDvB&Gb{sA>ILuU`ZoY{gRP5p`Yzr*|n) z7C?CeJ?y5Y@Q;Iu63L_j+YlF~R*ajG0`Ux`JmIQLc+;p`%{+!}M@Nj5GtcZ<%&R?> zh!L@FvMVQ>{c1`-DH?zI)r~oG5>a!=tTfKlW7>;EMs2sFGQlS^`_gd1+d|f@{+CcK1F`_hsd+lT{@3dAoH_ljPLFN7I@F9#=6VorBvftFdg>qsBcc^h z6*YvAgt6ml7juO9v?k+*Op#?;?nG%qy3(}ALRHWua3%IOSAHDxhijz$Ji3Q=`sF?{ z9A0Hvwp(W5fop&t9QL9GcnNTxXayb%BBCror|gSk0`6mB_Luh#(vmHcBuH#veX}~7 z86C`~BCvv`8=PD0ird*@r-MlnYJ`U|gy2TAW9M^O)pTofEk|i+j@#csdF_?tHq$3G*MMXoPt*{Cy<)~9hphPo{Oz;cdX61vB?wWxxN zBBN@Fjp2KkCPp_2(2!mp@h(BQ<+TS7(d);)s_!x~JcUMRMTro2>8g%j(FAdwnnlot6HLi*xoUDisqa263nn2xNK|oBEbtI& zKu-gp!YsMKZEk{Yv@X<-h%+<4bB^L zAao?@-P9&vTe9u9I}n=Y~j%%Om>p$OJMyCf%IbqKySapVddTw&|1heq$t~0>@ zh=F?6Am4}8LCU63l=QU74V<;4pPW|CN7J^NX2b2aT=R+RT?wB{PA=Bgv3h`Fc4myw z#PZ<`U#<4y6I|9x%q(xC+vuVk)NTXfCkYH0w7R0e_&Yc{FCUY+G6J&_;;ps6rI4B- z#|FSadRK~>vg$8z604vGRDc>*PL}eqgxVwZUP+1xu@+eqh17}_bJQVAk+G_o41@f z`-4qaXNTN%nPiQsC`Z$61N)aC|G*N;j_5tG^ooMH=uo1G8f9LuUwOsy;g+2$AX`5fZk!Vv40TkB^;{Tr{`liT0+=*N zqF+G>l5G{Ke=Ll}3-W_?*P?5Q3K}Xl*89n+{RzuCR-v%N>uYH6@SW%ffz3l{(dmMWs&kf(>GhMqI2_02CA+%$GGYMRrhpV! zA2Jqwr&2+W(PAh^hgJ0~78(-``Q?9u49fYUw zaMTUK%kOWNHA*Aei`I7Z3|&*&R2?HJ8;;=9(>BmXpl8qhv!98G@Mun?#*nqi`FmjV|C6XUZUwlY?rNeujq{f0k!{8yjB!iBg{2Lwh68SY$Jkt2)3?2U8kTB4P>^>m3E8P~=Y`iB+tzXvxgLDmM=o z&X<1aFcX(ZZ`$=FC!C;p38>O>CV7^*sM)L$WiYx+s4v3poxpCH^8qd@bHjAPg&CMt zVv3@M>Bp|Sc55?8a~&$#qL5~lO-!RCK8$jS>imsV%I+2xFg&hBsO`T|fja7p>T1K5 zl?$S}QY1VQ?Mxg};{FaQAF1py`3c<)AD4gl6Bfq@o+}P=bem+`&K5?mgMj7MC;RcD zGYT(SPE9x7=sZpS!74}1uA4^R@ID%)Hc?WXOdST4Y)O{h883HEorXtqKO~Oo;1m4LazxGzP3TjbI4K- zsg5AZG%MmPZTMMSL+X%dGAYlS?(1r<;UKW7L{qKfQQ9kf(KZ#h5Z+moz|PaYG{5nX z?OngQ?w+*$8uK%Db}5@tL^sP6okghz5i)t5xMS%W$gE(aeY3r+X|Sc#g`5;KIf^>? zxGx+z%qbUlibmB1USCdP;`lyB3(v}xf>R;)xQ;3dQ2DnAD)KGi5s9zEzms3w?Hi!h zAZj&NbI#!XFZi{OK3#j1>ohy)#z47NfaA|N7}-4Xs!NtR0PK3F+FMirA2pTwvXqb2-tY&zG5lm^~D0t9&<%H zRQ<*mw(I(Gs?H2usM1#!Kz~Zwaq4OP9^QQ+ZFpw%1$c++j1fj5t5zBRNiLP^a6-R^ zbnM|uoTIZPU$8neN4i9Pf@=3K>KZunputey!AO@5h2z#9d$rh;Qfy5HQ6<5&n4nB# zrsPd(wMg7sPJ|#}B3gXgHRzutYVQHqBWn-Nco}C|jjjWw5@}#F1Z|@_q?9^S%VCta zhkq~Tw*!ag!)1{T*5j$vCRcNdmp2Kg5?ff)h=3!G)=bViCs@>2%^wsKu%lbRDj^i$ zP=Z(N<=AIgp8CrHvU+z(?0Ny&<|- zQ?#6zNDnxAW7}XEv3n~}7Bd8B#Hd{8Q!uzb?clXJ)DVHDlwrT=jA4YcjIA*bh-!7a zS+o|${~GsZG<%ND*N;WVRICJHFu{&}WNX_dvQKcch03~8a&+~U7T@q^clvrgKAxbj zrU^$5NH5byV$RAb&muLjgtaJGnTSVWF06lfCNAn8ts^cp_eyr^qsDZhrbvE@myxKo zI|hUINEoS>tdOj4=X7sQJ;!X(@KMLa`Dn6`6R!cK8AfVqAC#n@pnSC)Bc%BcS6*XN zXe)sFC_nJ3vq7?J%3`z>>ARpzUn9YkiruIBkPut|a*9ryrALn2ikh|FLGG&03zotx zO5gXnoQYpRqMYTh+<$>8FYcGJVyQN4=oWmSer&BC=q@Zc7c2u$_4`N8N~m9lixj*h z_pF}1GJzUewK)vr5v88+!9d?dZFvM*ua^c0Vo8FKXr10!24_Va2-B^A|y$0xIfQH;vR@RVmVne9w2t|?k=_j z$>q*v0Ql5h(@F0_JiC-;AvkHBJ4{4 z&>9VK@w?sEJUNs6a0=NO?|zXw%1GE_=66>_DK3Dp5>Q5R7uJAsJE z*zwI$?g4A6b6M&&Oj6^f1JD^OBR_g0V1c&O>PkB>ShR)jD6K{~pk&yF=8glp_T0a> z-5JgmJ;UaiJzr<#?lE=;Si3Up-3g|Ljg(Zbyb^?b80XCDlevh&1&MS^ZwgC*6q7OHz#%^{pgvI zkdkZs&RGUuZCzj8rZmjT$9N}UdU#xslVHp7v5CT6j!v7(;}t71W%T3!et5o~UdPH0 z{XZYm@yYpfeE|KxpI%=#^>;ttpXyip{=7fkhxj|*kEE0P+x5q`ZUtwLw#S&#|NeBL zX_qwee|BuUlP5hYk?mo#29KEILzb9TL=$FRS0*NQQZ-3s=Q+J^^o*jp+c*3~S$_a}CT zyOBT)s?|vF&gmu+ioMK{prnI!^3VLC*;srKMZ21E(e!mbAHw|>NId|H){hi?$j0`- zfPyt_04w48jJP;$Un}vB?H)7_eK_zXI}HG){htp079IXlGmzdlALObXj~fFCY$f|E zVC!Knb13rO;suZVc3#5QzR8ZBlcc2fSM z^kKqSE<)ugbavS7as*d(&zP$wPOF<{C^Jb+aE#RNq3U2icJwSSRtHdmhBGl`lvmy&tPJ4C%>-ANVdHG@r{@y>y|^Sk;>AHc{1u z>-L9iU3kMgQnHW73sCzoQtM8J7peT-LM&BtI|VLKvHyfi>H0Fkkm|Mby+xpS>Vk4) zrC8p5`unUNOVJAD9f&PwF|*TJtnzzYkWxFjLbTGCqqRcS%Y&X`RVHFbhF(e51Zr(6 z*}&~5=-cBt8`Qa2dz~?p>3duwid`JLLv7CELhReoV)=z+v;E2s4*%B^MsD-BR}!&HT?#RZdn4=P#A) zorwIAq<}6KXCM;1=dcS$5UqmiCjlk62j{MQvkvlBUPfiRdisa;^+cuh3Y+q}bCuj{ z)nv11iI7uV)ZmME(bq)9G^HKMZ57kqNZ&Igap%k%5o|0dLpY!0P_C)CXAzO+ABdvjAf-bs6JxJ>|Htfy}O(5Y$C$;1Rq*M6yJfwlGC_ zk~OKW3krT&(xu6rpR}u>HB8jFXInW5`LB(4u~~=ZU}iOYCs#9Iu948(2x@s2DpYwy zbN>p0I#QF)byA?~MYj*Tv)D#|Yg9RaYV93|*735S*Mn1fcxSGK)E7@n1BhrRE6>v& zy9)c#hTgWp5<=28p~gComMKJa*z|mPA{KX;2nOQHsD%#en6i(9Jd(g|w?}kq5E_6d+=5yAn zV@=86Bzi^LVG#7biqEI4$YM6Nrrj)4qCtFHcNeAm4k&ik?LSFcLC`?xUztT|TZEKD zb3UB3DbLmJQA0bjh3_h-JC36C3oThAX1qR{f;ePKati?t$U9?2ajcIXYI5Om&^kwu za^nbj9{Qwli`d3$NhR&$U*=cFpz~gbbgLFGz`BOK>UIp6_=ksfZ^4oWV5u(=;7Ap( zPWym7kZMD%EHi5B!^$lie~9rHBjqo~`krv>8Vd*UQH1Zy}&J1I7oUjBrIc{=jeL|eL$T*($Fk=u2F_K$Jd{(b? z^KOt-=MTUb5wi(Yj^Nm-2xqFOq1#gFzap(Z4}v6KDR!04VLvpJMD25(MZA)tp0+Le z%G*aj1D{+%gMY>0vFG$qu7T-=W&2Rc?@JswyJq}W2Q1NS&aXU80BCKeNzZIPi{%s)CgDSLl=m?h>QVLM-vJDUE&@*L6q6E1N*ISpDF2y@B<73IF z!J_XFzIjNIm!7|>HiCfT)E$D2iz`|?UDbBc=1#?M>-H+MHyeeWbTdqPPBz7>yS88N zu2)%=WD*4(=8?$(H=Utgw8yiBg7W9U&}cK*mlCK@Pmruy4W#mW(RYL93gm#ON#d=S zX5_S!juH@NN(BRL|7ID4Y?GB`Tr{D(@J zyuabQ=XnR?>LX-cGn`&de+qTO}fqV*2`pP*OEa@YBy2_H3dVgs_F=JHHJ$reFN|kj45%(~K%H=?mJrm`nu9F!n*i9fvw?JwV zX#5GJX&q}Y!fxFNEWH7F^s+U#>!|5sIiu3AhqNCVOx#-D=47FhMIbW8+LlYfghcM7 z!E&l;Mr?w8pMIci;AAIGd9>pDs!G$;49-=kX4a61Voq82VFt zv9YY>JebG@smN8>ydJAXj#c%{D3?&OK@JEC;XgtxhZr`4ePgfO@G3^+IHXiF>W*uq zj8E?YZ12+aWTW9-5~Ho>amK}Y+j@13j9MZ41N;*+Z9TeUO&}mX#e6I=?f(>6&EU~s zBY}~~MDD5jFsRj15idJ>WcaLlDm88i*>#^BnlTm{da+GAPKkjsq{*d$Ii zQ*)9^(~cDbGG<_fYjuEwt+ITU>~N;}TixmDr~ZX(B7So%kp7c0{5(c4K`UKFx8uZh z_-iyjWuj%E*_?Pi2UkxHf-pY4jS!F(Kym_CZisvArF)Be9E}|ezh9a*FR6mEa~#WI zvzWLZ8#~L#z_NwfV`9tVTR<(?6x6St$x{1PIuawh*+t$x3Gr5wlzH#|OHft6D#gyn9ypz@~h74U>s-J<)&M82OnR zuxb$&aD-!}(FpK9%}m((5C2APnhk)D5$jYn_tjfexg^WV48yCoSoCHfH0Tqn!ih51 z&LK*JQWmt9i8e!FmWfZkYN%sRQL++=>PP-;WE2(OyV|zIB&ym4KeuzIfV&gID^{$;)FUm)3E7iuy&wy_qG%1ywbBy~EHRMl}fKaUBVeB1_c-eW1r|rC!Qr8j-Q%e2 z99l~mGi7{EsU~8Sdupgk2%@ zT@LA}o$SEQ7HL`1DOb50+}ok8RFIZVg6h)8AV?;+hD*AfJ(X_Hcz{G64+>6g^N ziM4Fb7sKlrMpcE=h@eC#@yULWj`0?~2-7_^wu!9ndV9XIz6-3t?B>NgGHmr90hNtI zLt^)zi;-y+KzG;KWf+Fuz|ME0qXzXNm#SV-?R(~Ly zpz)bgoVz@|JicEV-Ae7~$RHUN;zpPh;@;=@5J3zMp6ize!@gTwfcj-0rmR`mU;D1m z^ddI#D3ql|f%2T7Tbt-8IH`mCyHb#GZz_Hc#(3@X_e*WQoKCaWRyEM@Bx81SbN;jc z`}A4mLpE~{pwtYl)=pIZJCM*acfS18ISQwi8X)Ucc;|KpV}aXpN2H7ej&smMlS5hn z1uwvl1JYF>6wK88K;ePMeBT<}fwB&^g?K>9#M>P!UX7ZDC%zG6NeUbcTc;8eVP^dM*GN0`lxST zzD|rrv5)N5pK*EN6{*=_vklR++#jpyg_cJYkavA<{CLvVT6w3tQxy_5%{nnq+BxUeSi zt144nNC~39EsTn3c?V_gKA9S+Fukb?essQ~oJ3gg+ISAr<&asbIFJ*V#gL)Wdmd4p zWgJb*RI~^XFYDgq?6vU{D$irl@4g>)di{RRZ+={EQY&xS^tVpu!F9vcNk{U>kp;J4 z?{a1Dc_a}vAP;@%my$et5;n4ORDP(9JKkz%{8!&GMt!Xop8Y!?jd0k4zhh8-OEI0W zJu7>5GPB~<{GwA zDThKP7BeI3BfNrS?FP-EA)I>vMnuUgx0eYgsJ$dQV^DnDGsHeiIgLE2qJQomLchq9 z-uBcOn>(FY!0jwF#gJb4PDZ6l-RikrH4$}(v}d;5tBtDO7JOAZj~$mZF%h%gajns9 zHJ})9eg#gz$zI-l80z$564I9U*MN&2M<_@FpDs_5*0%b(&6o@jy$2Ek-{;w$zTeNu&91kX$MZRw@9o8G!Ia&tUhnnKlgF=xMh>XP;lNZ;2EnPGptk1_z7WLxbg75l439x=x$1Ca4#4v0ZG6tsK?{mE0Bhi# zNGD^=p83v{y7N(p4X=+w<@AY=rg9f`m{vtddPu@smj62U{fZt_-M%UJQ{i?UAW*6w zDc7`dsRhW4ap{{{%cA}xUwq^(`CSG+OI8$fY=)`3T{g{ap_xbcVh`6ev!TkJMCmKN z!{!MGCKmACvM7-R!C%J0l0g(sLc%_W+YUlOoVehFyk1Z&S(`GAX%I(CF8&kf9kUAb z^C(`YPgG6b59T`j76~Nq@PCG9k<9sXN7w<{aa~i;be`N{$piWof|<%z>GtPBHQJ(? ztiG9b6VZ_{J`744D&Zu-u;G*c9!6Evwes?fy_un%>=fRe}H48a=MAsnY19T1(C8F z@^QEJ3YL~%adX#4*d1)_-Jjr+!1KO)_h0+DG>~k z${!dkMR895dwb;~3?*X$4_0`CI+JTg>0@nw8^}ZYzHgJCQckIM&G zbv^r*%zg4B&cyL((qejUCzk6Ym@!X`J=dFCxL(v{zZpvCjP>-V2fih~emu|QJobR> z?M7p9Pjk(QYYjx_kAV012)ZC6x}i9KrjZ-YIHQgBG4av^2G|>{v-WlI5fE*Y)L_h& z({fk-nvD3S{m3kV}$-Fh#u5KQBM?TMhkJnqL ztmB}#65vXJh@h09%I|d+qLY_`sJ1n2i05Bt&KKk{LE5|ZBeq4E-X}t;;uae@-a4uC zr2xBIDq1VI=WoQya?M;j%u-0z>wHGdA%_)$S))XQ(PD(V^<(DuxM-W>IW*cySe@*) z9Y(kH|FZIK%hms>t-*2|MRS7Ead=Vjz_U5dus4c_z0ZrsLTk(45k;9c(>6!MK&cYK z#r7A<;z9=8e;o3aX|@5-Rr8c7iwh)UKKwDJpn#&#{tbfW2V1fN|3K_&+l z11IP%OARCs)0sIFn<*DKyjrL0V)X^}=h!yi-60vX@8rE%eolyi=y=PofYsM3oIz}k zLx^@veDw5^Xgf?V*N4$zY!3FPCrwgP6k>lr`x!T1=})* zju3RaEIN@;rbKz$iv3LH{(K(i5{(8nnD0~)jh)SJ7QUeI;R-prPr=8=ScGQfkyAd# z8MXP(4^r03PB=ui)IQ^aRnMuL(2d8~iBU&q0^(jtqOV{WWmiLfE;6@o(y;?)p2VRd*^V(pF~se-u#7Z2$(; zC|Bg@Acxg;Uws{D*OqBBAwG$iATqLn94U&*TX?dX)qw~UlxypjaXL?W*7=;jD)Njd zeiY|};{z#ZXoD0<5=_@ScrWW{WJYB_;K1|i^dQykCm1_M%FaR1^tlz@^}pT2RBs52AbT#jDQY4N zn`*b|coW?&to)E{9}GqoCO% zoD1LIufAVpN6t7G>#Oum{qOW26ZM<_D06p9-K=j>ZuA3L-(sihIDyOn<+4&GX)!gF z*cIejlot;JVWhQ1;oZ#DJbGQ@U061B>gRQu;w-MJz`KyUS!2-!IgfJIvaJYHs>C{o zM-bCuPa|L5ZNp=a1KlZK2EiP7gf-d3=!e`hCxfnN6r8u-?&;Jb&yuG+Z`RU2o{ZPz zGb7O$EUyt8Tmx71OWlhHP(85Tl#fQ~t=PZ}~%r3Ul|PV|M@UA=_*)A&DA8IfKXrg*NGtgWL47Xv6j`gHKyCgT_!@01-IAGI3m3o%g zOcL&xIMN|5)+Wa1pN4yaxLwV~{GMf4G(?Vd$o_FazImXYa4SqZtFw-TXCmdDgu^g1 z%%KUolWyfyrS*`AMBKg?x_B9E;_Sn4xrqgI)~dzJtDKvezd?0A;jLwX{gt}Ic#h7+ z9&Dc-G&2>e-%HG;w#YE#Jz9E~-9_YRkcR)E{ffi^Ui7{3iC{8Yr|0`U0Qcx{g{dDg z{~n|swWU2sO7wD2FqL6S#7r{08O2*mb>R!^q`DdunbgLd77O)5-s-HBSLr<^gjzCr z=u2a&Hc~ndX%+0(q9`49+^f*D?q{QMX7O3u>!NWs7y&IHyVM#w}sx~SA)O;_!O<9kmg2=&H@wt9?C}&kRPw8mt<*HdH zh+5~On>nF+IM4f$%0Hr!n}58Bh2W%mi2?J`t+1jgN`q)A!iQ&12(OXP0?PIv44I)* z?MfCQGJ8&0+*!Zu2vj2e5JZGvP%qvyg+c9Au@I-c8R~~uEY!(Lurf8r5jZ{zA(fuH zm^z>l=GJb(1=parlpG#Q$OzC{A`HX#{)o-6GF#M&Q#4evA4Hn4h>URHmKeemX zbsPLdkx@0!?ZQVsg_(;-={5;YP`vd^nt^N8i(YrCEG+Z@HK9Ls>aEN%USq}sA}=zX zvoI0@C9P^d`vxQ5qN0jkW4M?&6Hp_&un>Kswh;h65CdH9?DI5Q8pqh*EHDBs zy@NFpv*ie4JYADfQ9iLsTy~W>UNRXZcWosOQus2p|z+R^Sf&zswv6KICp5E%E6Wwh!CFAo-A zUoJI9ot_3dxq*@VrJ{LCyN%% zlG8E&U(6RL^CPyo;!;W%0YwN0EcC$E1E8@kuS=}wrx>n{9;5X-aDVD+WB)u)NrFX= za5x~Q_2g2P$quwo1>7 zSd0;{-BitN9RZ-xk*J(5;K8T(im6`TU-{Y$ z@?qDrgx>Gvcl|tTA;pxRJa*c^Cs)pHaTW9b_Ws`~AHSAvv;RF%ZT5zr3-d@m(&Agr zm6R!`sxZ)NMrV-iikAe$TPxxvh;b;WAbB>(BvfHi<%2_8I#-{|F}=Q^POpCxXOuUz z9ch_1y2=)KccW{UkR~z;E(96TQ9-3J^dnC%p@#Q^&ePxZUD)a!1nXT6h!=ISHLm{l|)>uCx4QaflWc zbK;8>H=ERn`k{ciN+1+Ilsw-a$Ei7&c8D(Cus>B6*f*vd#ccW7Oh9iS2E(XKHbG(M zMjqQKH^zWj{HQz#8y~q+^ThxKuX^G(ZXvN2h=O^78n4?IToqQoJ7=NwoUPA$$CBAV>Z13h)~K<|F#yBj)98#T9VsFL;n0<|dUf zr(M4|AsRws8)#*U1Haqat+K*j&St1Kz~u0ZjKVps2_~;2ghcDoZkSAw0vN$xHw*mb zqHN(-=z8gH{z{<|8>>?mpO4{Wdp-R*zdSab=dbVwIMyCI)E@YUoU1!P3UdDJPdilNz zTX66*3}$*nhjuI}AG9-9t^TW7aEYt=kyY$cSNea1FYcSXRE7ND5QccH! zVH{;)$rQM{&cUs$?L1r)*Qc5<#*aQkDC$vcprnc(gTCa&EX_~0-K{X>(|!Ls)_W{7 z&^|-Y@u9t@wz1muN7z-255vv7e?hMg-|P z_X~gN z1(zG^bVn6TRU5Qx&Xq7h;pRcLFE^Yg5>k8l9`tGQEIehr83rZIzPb$ zz9n);CbbCz3tOqw#ay7PH^{&GQ+iwAI^BvWzsp{3*N01$ledV2Xayi2!(m)*tTvw2gS z6#B;6n9QD_tZD+4Jb}TG>IqvyB`yeG-gOZIy@27R8s*w(u8Ay0nR+fg4l?U0V{b(7 zVx*3@=y3F{y@(YBveR-5`WP%ET!B-fXJ#&pqn|Z6!uXDG1~E&x0-G@&Y%0HH`pP~A zbeW%d2sV$n1e9)^P=deOPL;`+8+z3an8pl7)+ubq6?G=W4mnII*u@Y+{I%Tn`A}jp zjKFhkijJ`Ri+vPQvJEZii?SMqAyqlZ=8nnk(Jm$0>k2gGm z!0d)r_U9ulJwj-5o1>UlekEIETOrKxIuclB^giAyMVWGP#!+rYYQ73yOHSZkfY(J8 z1d^>6dRib7;UkhB8`>fO(VAElAd;3HU2z6v`f-%V&tW2T`DABIafqx6I!l!WUm`tj zWc(W+Y8>QKat;RZ2%GhF1i-2TdJSO}cgJkGirh3g!$wmUo2vqc2x|T2Suv^v-wSoA zihh*5^gXorH7wlxkTMhmdd@c@6&0127=+n&DlL#dm0nD!SxGxP>=$!COhC zcLU}A^T?V+W*Q0E9a3p_kAF`Rw7J#Lwg_avZeOrM5&O(8ncC}ZSN-mGa}g=eq*%%v zUbH&jcgGdxh8$`Zj&_=;OF;qQBDgExN|1?$ibk#p1HJp{_q|RtZ8>SZZZ_CD`T~}w zxC{ToH5!cn3N6Vj&fvET5e(Py0GBCf>mRp3@sOjFxr&D0=zuSscBJH+8^l=9K6P&; z6>}i%cV7AiiN>eFs4+v*H+2SEK=5k@laP{S8BywYh+pw9B@97kTGvTo#|ZJCEDbAK zt-f)BJHSNW=Lrm5yhCv*j56nCoOi&4JoH~v)w}}2UD&d*Xb4xJW00@rUzKcHF zb^iJrm?$rs-nz=$Q3#>9sNbIoIWxMStD84KK97blPa)bSJ3;(XZrVt~IY``CG#~9R zelT3}`m_D2w4ub&XVUs?yzb~E*Z0Yr%_E{w!z_iEj>hHMscR@5hQqNkyy2Y=I|AOu zY-<@;^R9jUqu2MxAKm&MgiR<3sugqD=kZKwPOje$t4LLWUY+@~GB@D`bt7LLogT2? z0EDGds6aim{OekGCy%xTjQxV_30#Y-lHtm-sj+ps|L;wgj~fPPiDLbT`%!?sj5n_i z*)8dj>pl=}4Z_wn&<;(-$Xf_o_dsFkx-)`ZEE2?o+>G2M`99Jq4&VNmuDl2*lJPlcpvb|}T5Mxg+6@pRt$!J~RGrF$7Oo19FF*uv zc^bPt?d+B_0A1@Oij1$>bId22L3fclwMAVR*si^;e|MxGihZx=d`;Or_}j)R+SKP{ zL*{1~k(wbAlso+&?7Q={iw2%q>pv2C=CkjTt`;$CNbA>q^L(;5O)l_2k&s2*)F!Y* z3WCoZio1v^b2{@SCg?>11T>MZqT)aoA8?b3opP_EC02MQ7@@S!7sURQI&2G8QKCgh zV5@3Fs$r@X(2-noQ*NUbq%l0cp<<>pb>S%oKe9MPJo z_YI}~i|THCU9;Vlx~iisl5aMubaeVgGUs0ooK7|3spP%cL=+a+HxjABH7sg1X(Ogh z{ioloU14rZ(L)NG^c(PEC}F^#RY6sEYr!8g-HOYiQwvWG7VPFb;0aGJqIiS|Z4$0< zoYXOI_~S;5LQI45$jum4a*@uur0$Sf4w$`a=XTD=_LPg|Uh?gv^wTa!nBsKKht_9! z&bQh)RQ|KI%8teCKfA_25{58~` zeBe5*qkqbU%K6`_bH3K6=ia6&=BHdMum7D>{*&eRD_y7mcYVc)TON*xuxfEvJgFub|yfCA*`2)U2@jXUiGC^Kcf!c4dt25+b^#qe)MWk z)ZUebwY@|Ns}%}Xy-w?|7qvl3kjKe@qv%CBC?1K?{c7w78ke>GGq7BnM^^-JM@cpzDqHyHF#u|)v)hwE^ zKp|;#VGSHZ3#3R^;Ogogx{%cOFV>Ee&+)6lGDTu$aw-T7b8mqZ`0iul!&=?XC%Pj~ z8x7JiZ&A#QHwp2Pp#?!~ap9LQb7M{w|KJ_Pw)xrKwsu@$zP8y}CD#vb_7)A&)NMUc zH%e^feJy%7G97Vm7rb8(Oc{_(p>dp@!dSsno!JnZ3a3%|y6LxU6ff2me_d2ZK3nC! zk$J9Or1SjM%$^#`-I)q|Z@z}BOk$?gn-p|&0etybZ?`|as!w<@ zSXs460LOF#FOW?5`R*g?-8O+`rkIgK6S#-Ro7<(A5%VN!SemMWg_&1h{xkO3g`CTJ zw!a%yBcmDFWy+|lx{dcf4H?F2+^}Qz_)%!lwb+{E3F&!C4wvm0c1;~ZK*C}{nczE0 z_u%pKc>sNAH(^|BSL4boyFK2I-MZRWJeU{YPjvrMCWo+4ib*cB;uQi$VhDovxi1LQ z!X+2B*5X?Jsl~R0M1Ru14aGOS{os6^lRj1}r0v62q(#Se-ol(zPaw&hve|oiwCV8T z*sJ`A7kJAA-VTq4bm?t(e$~36iy)C%^KXXG%TIN?Rtc9&J<5h4yC?j^>j)TXed1~i z=UD&@M=P5N6c`lXS!(!$tPT3nb8Mi*H6cf!#O_otE&>T~7!s%s?8_x4RPs!tFpDA8 zk&xZ_BE7a&bxkw|^>Kmlyv=!`jh9KFx5Jnk2$crpAcsnQ$Z~0UJ66;$RY+AA23+*= z^=VA#S?##llic2L%|Q++$>KK}E;kcDAf@rM18K|YTBh(+#)Phc_u);bnyRNd$MON- z)c}=Cq7v54M<`Z(OFztiV0ByizIIgq!kmrBF78=U+#=rWvRLwH3#NSHRbCTS?ltC) zobZlTq6aajNboeixLMJ(Z3^~j2^ymhUGRf%wpE0t6~Z%gYs$nM1-NTmK0V7n!S+_#?_BV9w|Gvcx7M63Dp2-{A z00dxWJ#5gmb7;xvvi|cr)efsMt<5d~M$^?>L}WBS9x`)UM?u)qbo!{M5P_Lu>N*;% z6RCA7E#O#IDRId687%+aS(87*mLg3nm`T~|E~gz0u%sxUx7kagDaZJS|GM61+-Le+ zywL_Xvo${=ElTG{)DH3MXHhrfS9OYyiMV*U4&Xa`d@UUmBti*1TCmBvNyZSl4>g(@ zP#0=f^<09B&_mXvv zbTO~Zr)`sISWx_fts@*^m!~l7<=E_-n;6Xi)xHZv+VKc5tetW2*U=(D@RW*gB941@ zNr4hd!Y;pI?H782i$Z)hp>BONCZBqEWWDAcx)g5J6}}Ly#~O)5BKaFwoT^Ntk-2U5 zsy~~SaV9)J&^}%v8SgR!4GU}21(~FQ9OT${MGs(9%GZab$`39whgVQspOrB#EGgcHRE&jhp+w1@O#-Wz1RGQn)+mPj4^SQxzaVc+GpSJcI7Yy;dCY- zTd*2xXo1DvN3Cff8t{(aCfuRJUlWZNWu=)J80(cs7;*na{)%~$^&hV=B%XJgZ?8+k zX5+J%)zk22-+Xrq)dot>QrjP+3sOk^Eg&g}AK}HWUl>uq`JZU!yjvBY>sD!jBCxmL zYvi8L)pdY%8lAsHgVt6CZM@y}7IS#P&^~1o20kpThWpQdAhBLTVzJKHoVWu5w&VR_ zpl@*;h{`q?`8R%r%+iMdUR;6~2(Rx`G-G7j?_yj8bqi><`i z|Ee>K+iNWSLfg!|X_Pf}e1jP%@pGy@UI0Xx8Tm%~a9r~P>4YrcL-poRg5F?geG6xi z(-741mX%JT@p&~pT5n9@Gj(hqYb6=Qc$3>kY+oSi|J|jdTWuT_d&JsXY*TvOrJcrZ z2LHa}c-BqX#?Ci%q>h2#A$1`+h}%JfD%;^|aCILz@2|-omd0I}aHo{Ouv_I*RO3rnT@zx5Y zS%|7poT%%Dj&7_+E*2(17Q7Y%;6qFzUu;uPR~e(u_~(HyG3)O_UCVjv7sD+F=zTA- zp9e$a&aw7yjSp8dTR6OiSps-12&m_oJe>&5e@WF62h!0gksu(kSCE>bJ%^?wQb9gQ zsKJ@^u#~@9M|>Pq!Q7Tbvoo4wjBZ=As(h4FkafC1!F(Gb_=<=W#B;{NdE^!Exe4pa zC=3B})hh29=(Kf9C(t+V?_o4r%eRL&G(8S+50g5REy~#u!@ZFFP@0L$z;w20CT#KM zv(Z9cZ3IRWG-@EEG1h`t#VKa4i)h?a7AoetX(c!cZ0jA#+z1y^C1u7>!g>Tm!Hqxp)T ziTWh~C-rWHHyKL%y`$g!43*Y+Iey4*zhnrmt_^m0FI?0bHQn3ABTJMlls42_P0%O! zvt92GRWS&~Xb`>oEDNCr!!Y%sRKa)DsS?ayUdNANP?5DrO+d5H@*cHQaNoOu@m3X9y(t3Pk$rK(GMXCC)E+T%xe^Hb^G_ zPO-Q+O6>Q)sBa*q(A#0V0EVwKbZN&`IJvrtv3wvS;@O&})pI zs(~j`wSw{mX-G_0c+^lW*}j-TyE9Q!(;{Z@d;>Tn#d`Q+s>Mxk&9e{2)Z-|RW)rwH zzH*G~H@SzckU&rIs(@A{m(H!S zdgsz0HK}H(%#Al|j`@aO^;SR5wnYYjO$oEN<_eu1W70%^Fg;*L+mMg1E6pS*4W!lJ z?9{cJL9n(Dr9mk2MCGZ`(U}du1LDZE#R6`j>BT90Kc2k+ajw40kGo0}tSyt={O6Cy z3W+o_V*;3zW(_1ClQT_e)YrK8Eu163Cj?hx#KjlB>?$FhC5G+90Vxg~DOY@94B!C3 zW_>lK$Uzg%s<;fIQzfZcF|@wz*l|6R+tAn9qP#{=(kE&{A|d{s64^dvRmk3H5?oz`{0Rw*<$O4Z=(1||7Ct0#$u7Z${QC4<}WZ$A);yq7icG#$pRM1T-Ql6ecBbC!| z(!c*qA2DN|RyC;0&kL*Bl@GGErH}m=WK13aCF{eqP%Bzlit?2&-3Ta@rug9JQZU>n zdu#v)1>FzU@~{u9!&TsTV?88KFT`jP9`GzFKB~M%UI7~;X*?T;A!lAlww0@m_nIAZ zxl{5N6#?quE6>xO2a%bmq$4ti-w`Bi9y_O}>LYIcpMb3^2(U$ZhiJ=OQL9+`9l*w>i4>*G+X1dbgZx5^sjys=E$YG}ncIF^Qh-Z076jwr! zeTqpai!}QcFuM20V+>IM5#y0$&(Grm5FEA3!mtZ}VaknNEr1MN!C z{w|ib;Jw0%l6iIW!<6!;ENqC>+GtS;KOHU5(0ugs2b7+34i3WKgmCoDc+V=iJG6^yMr=+P1r`wxwlGb9y&O`zqIRLuZ<^$ zRKZ$zz-9^o?!>m&OJLUO|d9#qj^zh09zRuYOV@uFREKrc5YZ(Ea&z-R=+ zjCL8a4%k3U(4P{HI?M#^L?wYDN3E+-@SEvn+t)f_ytt{AJDkTNOMsgIrFM%x`p91Y zAOy`*mN8v5_;rM-o}@rUy817_r06k z+{fIAs2xO`d}?RBH}(^OI#NR%_EW@<2?vP&#SbaSF(fg7+B@~~0Vf${o~3lQ zt}#RgKDE#{37VGnd)!t)^ywIx0Z4;_hhn{UIv7`6$0B-%a!p;3&JEdy_u70@j@&dL$oWVq~BC;yYoh{sK%uw*6Uf52)&0Rv;=`e0<^DOFnUw zt;ZJQXsC979j9|=M)PdlDZfp5t16bM!ete7P&Mw_Ct(c^d^v+o1Re+|fUfXg>guIM zH*K87LODlkR8ukR=$qD`AIZtQnM1}mHO~}I3$jF4Mhmj(dD1K61=)=p39j^}#NWG@ zX9vdwf}N4BnY-Ut#En-ndZ>`rP879T^Cj*up3(dch7}Ta>5r)Hq}?V9S{;w5WOzM} z5Lzl%U11rmG<`txO_IPus25J*iljxA#ki=|_7Yh%LQok@!3QJZ_{lwJ3teH@hs;k9 z3?-E2^2<7QPR&)=*^fiN$no{Y%9xGQW+auobu424%#CLohHD}fU0-S=pqC-^=W)P*im6&`4An9k zN^>K~skK33bIvgPo9Ix7K18)2o)Io#jb2#x(jON!W?>8`sv6jdFQ}S~Y*+|GG4FzM z4B(<(oxbhaM)>m7ZJvs7z^x+HRP~ND>$%*-){U`tJk?3A#c^@*8+~W`oD}FoRGjc) zRT>zX|1(InnZhVJcLjerR3|;2W|6U#RbNqMG_aahFCk<~D)Qd%0MKVFWGZYgGLqWI zIdIE|h#am$L<4W+#(pXWTLv9J`>IDi)w;5j-4vdoT;;jj#Q-4N9UD_A#$SS`*xgjm?3uA&h{yOtl+d6y~TCL zr=%vI)!y7-X%E_RKxaseR9O_n5jFQglwK+hv52S@+*KwQuVgzPSnVut4L~8m^RyN^ zF?63XURNw}xscxpc47JYIM`F6{}^e7LcyEpK$(kb2~I-TUhD3t>lV?EStk z4SMQdUH01r`N;4yB~g8SAA^IHYe!~1mjyt*JrtXo|DeSOU061#-#vU!EV@4eU3Zc6q`Q%lqn zx5kfVk`)uE`$WHcsdf^L=h27pdeW>^KQ%IFFo3wuRKV5!f+&iRndY{FW z<50XV-B413U2Z@fG60jSN9P%qIcq4oIEdwA$-l-0$z!7cGrSRo@~}a!>%>}pVYs>{ zCHBL_^NHs=(L9g}U(7zr{u)n)@=&zX6W?5CMNmd9lA&L+T3X%Cy0sPPl-7&lC$4{} zV=hFb`!0_&xZ4~!wY&C_EP`XtP_cs1T9pfTy`7{_I2Pz}+n#NMa5h*se;CWSPO;<* zL}O&%nt%bP7m~Ot6svY+qur+ATuX_QBO_KYZdM&krK71%F!QdCz~}}Is%hX+%Q4R{ zEyyN{S&0oM3S3%9-6SJbb9wj%v+p~O zG$xj$!UEN5&=pl!EL)5V7D}CKHUNCJ6Ck}>O8O}a+E8oCRs34f^k$u zy1|R7>`YxR?fVdG(%hRF52X$I3>cJ+1Wkdlf}jw|Fr%o8n7emqj=#gW)d?&rXnvmU8#bdTApTLj)2 zf%oaNT2zU&i>;TmtpIXrWGK-;#6MYEn3bOz2H?|0>IFxG1>bAKh_%N2>qc;^=RUm!Xo zZ5Mw;g$IFd=1=|)WA7B6Sr@!{$4SSwZJQk@9iwC0wr$(CZQD<5+vwPn_y5gYGl$>F zuD#Ye->Yihcm2v2zeAiajP5W!;W@iQ zE9Xqu!OO!z_MBh5eCkT>bDkke`FXW`pvWH--Gxkx_T=yZc7_UferCs&xUL3-T1qhQ za1d}*$v|LFZ${yJS>MIeP{=#gwjJTzJuz?&yEb#{#l=F{hM5UCs! z-jhEZLRRAH<}1NCoO)nCTCoiGJ5Ydvit7+dxl{{dhv<>fg@bgasHvI2 zR;2<~au6Z_iJK;z6*69dJil5-BrSL>P)7JLFe7vU^70Jjr%kJ_y}rWlcyX~*BvjicvIu*;%;&kL~J zL*J12q*1gkNq*&NpCI|3BT1fZG=H0JG%u$@j+a7i5WcX69$Fd0q6ztwNO<|Dux^#B z$T;H(MOEkOWox6gHin_Htd%0_^ECL$O#<|JG$OH8OER8i&b-V+B#uKP@26US27bgQ|EYLo07fwWSl{;V%2YYV zf@cY3s}gGI;V%WnxWA6A78ouFlz~F!mbSCis^MagFlXnv(R}NB9oOk2X(60Zp5A*x zgzTT!d?`s~d0jCc<#d*uErxV%LU8v>HBmI>5Q@iiN?!F(-h7%cG7$I6fsZ4w()P}v z08~{DQR<*XnRw`{_ctSFBj({HYk}T+y)M*STwZ#mTseBR^RWxY8&-0?7!jkHpdWfa+N}{mizLsb%R+3Mqh*wvvyH9xTIY z@u6L1pL#a!YwKu`*LLe1ZLmPT4v3UYb*3At85>|zR!&axDl zw_p8_twZv(K+k_H4kD*-;*j94yP~2xx}DNZdKx<-D=SHE{2Cu>_WkjeCYOt9AY1;7 zuJ+}katL4fdtzH`uK@%^#AVb@eoM)aY=&(G`D zR2H5M2mVDqy z8&T}DS`03om6+vzB9V1!%(3-SB`a5f#ochcFw$ zF|Ci|fs4P6kWr5HQ(A&ceZB{EBD`Ulg6)G?=nxr{aC8T;aG%l@{Qf}CqPNuKjy=c@ zod1n`flJ9CZ173}d=!N}1~kaCg#VYRW}NN7AiUgD#jw_0%JhKLi}=<6bVnHW z?1bVo>1n3}rEpxSa5d+K)egj))#7H_{M?zS%^^@|8>x)%5RCglqM5vjvLT|lHG8@a zA2~-`_lOKx*E>84Da%mGE`h#G40RnhNT}0xIy__#$r`Vp(JwT{Y!gY^U&b1My2=X9 zF5@qwq_=>&iYhw*=IvLtFHmWO_5sSp_qqj5dZRl*X!)t zZ{=}GuescP!)BQ5?aM!{ZJe(?qSH;jTk$UT{c55}EMm!NC%g)Zlfl6AV?$MofPVM~ zUgK8U#)8HB;vs=)Cy&PX@Md8=SEXwAHun4B4}k8aSh_nih+rWUm?%iR4=u>uP%Hnw z2ONjx(@58-2Hp2Dq=(uznQvkG4fgNZ1-B{t+bZaN&nIN^FMP;!q(jB{@FZU0KSBZnQWYO)g@JBbDuH zAxW9QdpPxElFt5-xKPkh8XdY0%i?XVx{$Y|gB4UDt3Nt;VZ}SOonS(g0vpTa_S87m ztf->JBm~F9+)svNas7)1RjN$CT=NtUz}(3_?BH%`8$p;v`$viTy){Z<%RB*l=pCrb z`_8hSFrLq}S?54Xf1pDI|B%qVg|> z7AQV=d|A8mVrM<=o`|4z3usLN(JuEIUCM)A`&h9$7`*9-fQ)7>AFaHbqXYGWfQ-aT zf$Ew{M8`D-!O(F%m4$!4zjXr#H)k|OEaHiejPlY;-bF|HQ-Al%`ZkqR1P8)L$ByrY zPTH|;x0h@(VKEVZ{ygKCGe6Kj6;IIF!o~t0{jb}5r4&lxb1kOSOzYp$_0iRdGWF5_ z-6S#zM$}9lpC88qIHkyiN~AtJEcTVl<3HC)Pwh`G6#w#B%WoY%H^$lqS(c3S%OTUA zq>SmQ(pM*QQEBCy%E$;BD_uyeBre_`@AFt#OyY0iO%(OIj>xRQ0q-E`*Q&UE-?2w6 zdw0gF-`3Yi)IH%sfgbVW3=>r5X?8)WFLStT!yltLgzRWk+>g99>1}oQI|?U!I8pCq zd-iRz?NpWpbq)u|*7$NJYh%Vh*UJtMjhn=jA<~z_kH=-EZ@aH`{L`PApKMyBI3&hZ zm$Q)3V-EvRVX)e7{fm8NO?~R%bD?jt{U|Q9!Fu7Z@CL*#C}_-Ks&wpGH*0SL&uS~$ z#^e;~O*g~;Wj^HTP6?8OrU{Y)>gi5u8DV6yrkc1l+%r~qt8xK;!qEc;Cvhp}>vHqR z0V**&-QMr#FAWjTUIT7%I%ctTqfI|-% zH9oHP;)sQdDD#H@f5{Iq4<80Dz2)l|%0*`+P%6GXCwB`pWP^}H8E+mjSlws~@U?V~ zQL8g<{{PK=cP~@FtWEwj3i23wc zr`y8ha6UGUQ+p_dWpCVdj_E}v(DrVOe<2?FigP8I_R?d(l=y7SCxX&2fSgM7qt4M(C^}4|t5kIuir`edsk>DeDR8oQnQlaQd~0F0T%Ltx zFTD589g5MT&k?#Qc{hariNI19eeo6mP<@48l$D9X2JFu9hOff)$Jy=<1!pw4~P&6KDYJf;%5L@;J= zb5&?UZO=>P(ch9q()jX8nkurwbj!;FC9yXtb^o~#OCj*rpEfsXdzzkwC|XRmVuM`$ z4lwORBhg`G4K_u6)#S0wno(oSCs19rhziW^dfm-O$Fi{x+&n$;$t|Ie0w(HPPi-Wr zbV1qC24w4AuVf4iKbP$T0mhN57jB<5{>tasDm0lKSmlRONA(vh?2fc_f>wr?VAR5pTpq!ENBFLE>YE^pml4fgV=4Vq0~OhW$3_4;0}4l>_R8E!`a#$6p4@_hEd}z(z_y>N_mpaWcS0dq2Uu z0N7|qRG}Mhq4x_CBQ!c+4d^;~al|!uhlm7s(;Z8l{A@lM!kKm9W`wYJgm-^h&@nFHyu=Gx%eo zU3i9mLNm{!unI_kCRg0{!p9MeTc>l_Zfj=Nd` z&c5DJ0oNIP3b45$*h6=)fB=KIT;AJ%nCg2_C6J@YKiCEb2brtKUo zS^nWIRdNK{_GeF=%_h}eS=vJA2F?+){~8p%L>-9);)}un{+`;2%)cYvq515_ak~i} zd%jdj?^Z!7d!pXw^F(Dj_`A}n3m%<_;h3JH&XpG!Q!YK{_7-_Dv${PIe*5y>L;=!z zV2FUVhN&{*%N}`YO}g+|vLhiJht_>H*X%maLNfyhaC7CCHZk(W+*b5x%ozMvjltY+ZksJuUwdn|iC+Wn>WgvV5f_c1h4#P4|hd259?GCT2_v9Ikf+ z!h+}_w+#&3Ma>n?EzK7Y1;jIE%0f4qALV5}L3gM4{dE83!O1Qs3TrTl|KYO>;n&h( zjB)zsj$)DYnMlP~7x8=<-Xlx)=e^mJ!1nk4*TL{*?TzniRjm~|mLX5LdGlU%C(w{K zF%PU+yU8>#>Vh#u+Z8>}O5Qpad0mL+@8Zz#jdDS9BE`r_OL>l3-1ctns`L~6vP9ev zXenPwfq7-Ns&k|Y;&7!NfnV6T`iSS^A^eq#QAyR&!X6Y?IWzdoa;KG^p1;ggwzjXz zLy=}Oy8}07HruY(-;sf-P}I_+UcrGx%>qBkplS9f?cXdF~nn^&j5+C{rbECCwk>Ty`7Pt=~UR#(;}rWrcxu$Qf^nh9QqoFW~@M zx(ea*|M)m^*%{0l;;+FCzYVJ3hvl+FGXMBo~)-BsxvM?yDuo)E_8o=8IrS*I8XK>-sF4e-!2iFd>7+IfO9* zhc^w-MQTJ_qcUf=>MhC3SlsSQ5pF~fS^PBxKT^14I(mSpp<+YhUh(SCZ9vN?jhgN0 z#G*C9$nK|g!apa+LWaYsA@N-6_jMXv##^0j%(%+8`{y!AFyH?qInsn)Xz*FnSoK6Z zfy^AqRg#Bz`Gc-nQP&=F{uVgCCCJ6|^1iM79?gY^e|q-)`kHP{HLdm8gY5mHo%n$G ze!TbsTrM%h2jb#-Z55NT_Du(;OR^2(b&-lWJ2i%Nmet0K?@g{$sjKkO`eb7i|KiHN z|8m_5i`V&A;z<5uC0eV>uu@4}I^iqZap&Mw&5^%V66tqjV6i65r&-?)4a&)L(ce2O z!2e-kI98^W$aYo7L7yk{JmX>pZxsV+;)5qAZE3EhWae2buan*Xt{cZ&LDUrn-*b=m z|AHCgyAMEhA*fhM)w5P}$z@FGAp3x@Q3b?CV3Dum6%MBT$6QE9l`j%wVmz}V1uj{f zC33!qtW^PAa(TcF(~X^dO$+GU`ZmxYsxYOPYr=nHf)98m_v;;jGWs+wQ5|?#d+DxS zIP+NX0M~sB=zc_8d|jTrGC=C`G&FpF*4p}fKCMjZ>VA5-^!4(;yxEd)kV*~CplaTt z%MCM5sF4wb5Q0Y`*+|rrt<0ieY8Y0RNwB=v24Bhxb%E>$jPx=4m8hzAY^tO9aQb=& zdykh{whcSu3C@MAy7;J-j2xH5@az%JXe!S~byb)GNd@hxLo}g-ysSrYAje=-L zaYmI+4@yX4V2rB+F5`NI_*3cnnAGslut*<)AOt{8+_TaAQ1gb=GMSMA_2qU}A+~PQ__6w3tKh0D&CXBMt>frs{ znsH3nH?F0yd;~b!zA6I2v8&?pj%niSn8Hl_nMeZ1)6Qz~UzuzQXex~x0@Tsm#!oXn zPVLzfWxO~a%`o2IUZ7H!ENPybNuno2mlY*M7{hbj>nvraFoFP-Zhgy_RZqW--mtk! z$bupq#P;%wi2W}jNB5(P;di>gQg=d|CZ6T!A?yOaMHgeVGFd^URLC0-z8mwP?%@?Q zhTmQwlM!05xIp{@0jXmMv6vpz@Z*~1m)~6-C)>=f#OXdXa34o=xBbOe(A+b&r_#DA z>7hQNW`-{Ebq>|TLD2ul2ZYC((I#oYtrugjzRQ-Ys!6fXB~o>0M zMm?D^AqS0Bnx|gcQXs3(ouWJ~;L%nP-4X0wE>Tj<62}4%uCnyvtdJT}#H!jY@UOw_$axHT~ zv}r80GRV|5v}y-1Z5Jg~quHu7ntWfWfC4Bj$(eP+XpGM5q*8T zkY#o<14%X6HQvs@iQ$r8g@SLj#SRoB!)MO2zA_e zFRtEvjdTUYE#%~9cWns%urgV<6vjR>TG5{aw6zF|>ZTaAF%F!=Q1yEsqD6FOxd{WF zG6WIk2AWtPB*F)7z3GJ#Tq27xSpT<4d{+a;Wd#jI?U8VVCS}|*<1fsky6P#MLuZ+? z&$|NkaL&z0Glb0r?wbv)(@5)-X9uCBdIC>`S4Mbn5KsfP7(}l)bAt7hcbL6rf2cXo z+tt}yW6xWFl->40lm*`yfu_QKGYfDV94RMq)kjYp<|I(Bphg>LHGLvlzIDJ%y7Z1j ze|3+u1bte^(XYyHyOP7^Nr>LQU_)x}UW%t*Z`0yV={JiAA!>zyXP=_#!C_`ZdPOUH z6tfRE72tE*LcLxY&|1;qJ8TS+AutTpooT(j45|JMT{30m?ilCQ=-WM+0!I^6IjvU^ zdg4ijhrZ|OV?X^#GuZ1VfqYB|JNgJKZQ#v0kGsAlI;=}g| zrK<@ESJ|XH9I=}1UO;;OjV0vs`^5T@yz4t$vqxirj(>>c|n4HD$%Q{?$$lsga zyXftdle0$QnY8wF0Hg2?4{|BobXxoB1DTYz>SuDP&Hp*N{@F5W82Z^8N9Iu9XU`o+ z4h7f_BbzcuV}BXSXs6aPWR(-bF$2-->LN}@0UJ(;)fz5-oE%b6fH=c#`v6{DU%QPk%yQmY5cIPx zA{N>vs;)28CVRli0Y-mQ$%Jpzf*hmape78Xj})qinKeW9rBLVYL_Dy-FR7G%j9l$W5E1h73y9my?L%1 zt7-kn8v}ASR52p!?_t(t;wCmdLAI6np9E&qX=MM`ynQE!DdST#-*8^NI?q^O6w7pg zRT^9jSv3ukL64elPOBK2=)Zbc-HqJY z#j_Hnb>OGqMrp@-eKUmd$paS%jqePY_E02duW3@Dz>bFLyd7r@%}nDE_~S z7@S~m+y7O>C{LPwU{~wU5B^6H>%l~gfdDIP`5Z1gM)C|p%OVacp+HH)C#4ltI>RKQ z()o=|gUct)_+}?G2Z<7fPYuf#P55vZlqaVJ6w#wn9{_O6hXl*OEI^{T9fIaz3YdwD zL!sK`m2T^&tay_B_qgEqj8MbH8)BeO9Iyyspy@gZMUoNY(zseujv_qRsu?naphcNKi7v9JaR;FY`hrGQPhUU2v??l>F;&s;{%V8CA|H0 zqiLm`9W4%Mc27htypG(+3a|Soxj#Cp$RB?vah-b~*eMM+oH|1XQ{qbVKw(yjP**wf z(f-nB5~!*{S3{)D7DE@E|Bnqdb)lWeRk@HV9EX8PA0+WfjMTJ?nr-=-A*t(#YLMeh zdvbTu_g{gY`EyVGH#;dOc(ckfE8uw2SH~Ia+iyj?5v}{kO-Vqi`Xy0*a2~KL;ROTn zqo!!CY$IK6$7Ow$D)#_{CQofrx6a2l$q=bi#&}JMMW;Kg=#u=#6c&z0$U2C%%m&T4 zsiYDcSgE9N07bMi6Z1v1*4^y?d&|%Vx0W^=dT`M?Q>yYGg72#V&everE+l;A(hpT5 zWarHS0&iVf+v0i>!()R(I~8Kh_wM5B3&3FF`*|b>c@bD!`P~Ea#RK={iT2@&|IrHn zU4ziWzgj~-@5o}uVEP9;eXK>36P6~DFqoikzfMoeoRf_)3OP{SZ={V-n$Y+(B$85Q8%70pXjIPC`Q9T$q zYn=n#vIZpMSHNisNU*PUrQhnfm4Vr!=)qKmK|(05inH0k)cMz66xPev1tKPGW%*i4 zkx-a>7Kg_gJ&+CgGbtBaohjWZ0o#TC4V^EqFN3dw`y-F5y0x(950D-U&(_MSgD5NM z#W&dvc0-*YI`}CKy3V6+ofh_)((@1l%}-3=e0uj8Bd*2xJL@gwcrwMJj&o6U=)uPG zn!#kfC;Wd;gfQwYVavI=?qH3Rfn&rPR_v%3=dm?ojMM77vCi7Z9wdixuJ|1VQXZmn z0U%d`{Q>(0Hvyi$%X0+JKX9(?IwRF|ZkS(cOt5TL3MLp+L1Hk_kF7>39nPhP(1NV* zuFt(swcpLnIeW%v+yTrYhU0*A$$^4y_*($Zphw-+62tY9e*j6@CFl*Rh^0d#f674J zd*~y*HN2n-vlJVZ5jW_h92Ne(tCR@yAuJ)ATU%7LSE2%9a)J@TSpnm!zdRD++L62W( zLfAXoNW^V@Ae4_s?VdUsk5cq${Gxt)NYfm!*RjWmCWW24$r7QY$TVIcwQ(z%WDuY|S> zFMB@Sm%1)a-H$TZpwZgstTjJdlRlSaXW4nVD^_F=;Mu&1YhM@iK?u|eCN&-fr5;Fb zR{k0WdexdSrRR6oK}!VlS)E`k9^#6df~#*RpW$B;m?1D-7eT1A5&hLBvo8J)wG%v* zZo2G3fo&MNH`c>Ys~&Q^M-j0v|j)h4IFWJiJM?;aGZXFL)-wLTe{c|$Txb+r5p?X2a zX_jdrl~bu-d8QushRv0Dvh%(hHLzl7OL}YCq*49E#Il(=h=X>-AxEo(zppW*quBhh z3vo(jc-{Ii@L%g*!h&#d$<`4k#3gqkmK--Ou02Mvaa+ZQ(UD;i%#g{c${g@tfV~IP z2Agn?i3_O}k3;dDy!FUzz&6Ta}XB^eJ@tZQU_pMi1IG?k394PzQV9-+d zMwN$UMf+4gy>adzX0~aB$@H1_&3&ruAeR&TP8PcM@t;oAy2;Wm(ZvzSHAQO{Lcn&o zBh@rcjsLqqph6Cwv8z*cu0KJ)f%y{7Yuy{1))k+@L?YoQ5Q#!Drw8wFYtwK7KgpG! z8mBg9Gd-zzp>1Lz`XBPDPMCRw40C`pP0l3V+1cAEoHj~^xw@p1ff7SH=%+)kwp8P~ zqE^`{^udk_BfO=dVtn(Bp1HjJZB zp2fcek(NJ@64uKUJKHSieb!@Zyz*SdMFa6l^vI-vb7?iEOiF6Sbld8mKHI|a3d5SW z-4O%BRJ(Qm!q~nMdT?7%aRGLAF}1B#Yu(g9h=Oj2NSc);|AJrW!WHaJH~b`WVLY+S zJXBcLvX+VHFz(JqZ;pi{(l-t zIM{ zm_F>VzQ(5MEqwLz4G@m;XP^)^Z3Nn%DllIwpi%GQ{8}og4t@)ufieeSgI1=e|NT-0 zI6$1)0GD;qyv8wYGcD%LQEDdN$;ruEJhe`E_fnXQfyCqu`wGtz%&bDYVa2v#{R^Mu zK6~UP8kkVJ)v;evx6PCsC)i|G2$vXZS$9Z+IAV$Z0PGs*?F)Md`bx~C&129i-G&}u zIVGQu(tjCEKMbOP=?wS->hndn@L-6#Gd0GB-Ae~ny{cWVq5Z) z6w~7*zJKC3qJN-Ip`tQUG~WG-!V||4wVWw}#7ruU(%J;GM#S~(6GAM=^cz!M=7f^) zcr;&26sq!E7S@#fptBP!Mj|hZGE)Us|M38P8NqsT>2>8da_%WocNBpj)y^k(h!Plg zMC)#BUHEq7I}r*PF8cMD+XG6BSjE@(-`UVYFuBnzQ-_7?vy(3~(tIqH5pwNsx7aFcu!UkcX8oP8db?u36O zrhT7b9Xjx#rY=&DL6KD!>8Bb!9R=3jXlr`}H~Qn?V|#)y z3bU;DD>2Ss`ODE15fnJqglw2VV>MVfb}HKRSA(f|=UsL@+_(B)klj1}rtjEpSKF9_mM78gom`ONEb4@rso4hC zr>;sYj1Ef5UWQC!Kr&(5=(Z48foX< zh)3-X@w87VbA&>l;*15Bii~UK?}1s z4x&63IAW3GRR$A$m!mxXMZ?|W?8SsGS&pGO&Chq>#{4@jJ$7719QZUi$f=MSou7DZ z`|}2BGFS`Vn2)q$4MVgx83q~0;{epo1~J_B;u3hO!;qW#t~LFo%4I5+6aqKn+y)my zQ=c9144bRD0R zc8uz8)8?jw!2UW7f}>-b4!ivnl24X-y#Y1(;lbzS)q5e@^zozh>fPd0xmZD1i8#|f ztjton7B7p5aoO{dl>SG-BPBeL8!KicVZmss?kt&R2i3zR&Z_4jtzJ*sD7~E#AG52rJyjkTL7CGKgl@-nRXeq@S>#t-QJ?q+tNL%3N9l>{=xdr8{z}MXz)g#w} z(`Lyq&e8WDl`j&O;=i82W)t5pkYM?rpg3&PgQa4V*MlxvkUlW`_`P2hM-c4dywr3s z+!yy~ItQBkaq#S0Up9E>wq?+%25fV!4XAG&UEKv9`1!+2W?2IOiSns9Y$u&RCB^ib z7x3t`hRSU549I)6knvY&JJiXK&DIByeUfcrGB~zbntNzQO*L)R)T~jpo~7Ykrr@uq z^;rD-;UYmHkx~CXLXKbxPuYme-{6jZ;j`vN?976ZZs2G0lT+#}7pzP*iF&&PPTO3BIxJ%PB5d$#{$QI6< zX4%i33(XXJSvV!M(%$@V_dD0R(@AArRQw(J2D&JyfI;y@H-a@#{02x z1RmPTd47yg=w#`$Qv_tCBdeI!h5YN4JAqBYTEw{D>G4y}Pzp?XR}yhllL3cy2S_I; z5J8V}ybO*~+{IvsErzNI?eS7Ib$^jcaTN7G7>6Qs44 zRU#3GV@AN9VXW>(euLCp3TCF~wWiZtd}5HR^(Q8;#ZwiEc@VKwXr2v*lrG$itU8`x z!5efvmBOt#2O8DGY=0Ue4#CSiQ@qc>ybmmwHye5nRWPngw>zoMf+;G3q-*^tnZG}{Gj#WurVaPFWDf4HmMG&s)>$J zrx1}+CynmsU^y5AdV#vSV}g+HS1ApuFc93k>aZ#NGVj8VBcr0jQWA_5r!;=AZ#mM> z@|oGt&{JJPF13L{2?Tvs?<2c3L8E*MNqhziObdRYpSCXEe%;1V5xn1sGh(s)C9pv-yTLjdsiWk2iak!K)=7aJyZXH~xXUnrRK1*)rUSva`^C54j9ZNN zcUWL6Q09d0cUFlVZO`2gT5o3F7C75N4j4#sN^991 zQ8YigCdoneqx|c>Z;FxBJeac5+=v*LcW@G#*~%GIN@llw!Pt6tJBcg2;ZEj;#Chpc z0_t*LxFu;b9cA_o*$N?`Hz=1-xaRZXlBgMl{@3emD9S!{~A z1?ub0gcKz#+0AZe`xUSZS=e+BnuRabP@BU)_sJySf;(tt9WNl`d(l8RE6596-8bpf z{5a5UFuho^QJ-+|X0V{x97}U$0!Y^iUc}i&dz0P`Nc=cl(p!dQq!AVGtDhB*)Lbk{ z6L%R5)uu!yXuW0Q>MD!qPWi`TH6V(jvPqxALpJw^*Uxqk=e4c*w5_g?4f+S4(dHNP z2jhh;!1%C?0B`0DK2c#YqQ)q+I(hg2Re~wC-He zzqL)nslOj{bxaEb?P~kT-Ow?Dc~t=pMyOgOz+mFTu|~nk7Fb=6IWmSNwrxgNg>B36 z7%Ti)%Ia(?QLz)UnrojLB#*RL$zRm1T9cUXp3x^Db;>Z?z(ieduoMu-T)iD4r|6Y< z#695$H~bNZbJg8J_|1J_7+jb7;Qj4B6}@}JkFtufnTm`HATcy8D;&;1Wn2vNcL5+4 z0}lO*W$fgp`_YzOhzo>3H%2VguZ@}7m`8e;Pb1S9Rb1oRsgHbE;zVWk zT~0Cvp52Gmh*nk$`-Ux)w9ELPok`{+w_VT3{g{WT%%mp0D z4|367JiY}=H_yM6)Ym?ap}Zj-jP!>qUxGNsnJ?43t`BYIh*T|uP4IFNMh_k%pHIW= zQE-Kru6e5b_}A+AOOnK1)H)aT_VktmzR2MWAzGW;)~e+kZIg8qZ-2zP{e*iv>N{3Jr;-|D!vpKn z_X{$|;QeI7-7@F@eqj=m?OF&osR*hmjDe)jpEJHyYrnwGt9rCx9H3{kE_54yW3#c- z+nLgc1cd=)zouCE$aZKpf#h1d-&y~_h&~7W6)EiC1EAmM?Z{US0*{?dL@bIqDM%Fa zP7KLHy3W49W9v>j&c5UvT>61s-hXw&7^iYqYiK6t-@_fO3MLg*KhZ%SUi#BhfaKS= zrExW0dahjPLX%XfX%n__T{o=no#kN!i3ZL4v%Y-RH|XfxKa=Xi;IYTm{c1O%l&N*f znJ5AqGP-g5lU~9bxi3zt2hTxwX%;(_`vDydf9-cY%yoo=VCXf7IC365&8L*A^e;!S zM8M|hLJo#Hiu*0(-;`DJ#=i+{`1S*5TiadQJ6HB8{-4=cw-Nxc$pznS`ndMs7w=v0Ud7)j{;uxLu5shT znzv+{xwOrrF?)U=b}BfheS<1v_82aLq2UdIi4Eg>KGJfdw(D5{lxn9t*X6C@ z812ZNf`c*5Um6*FZT}yvj74EW4Jcq0s(ri)1>0R_|ZSBTuh^aJP@(80^ z4#{V~-cGVmw?s71qTRD)JFsUpzmr2mBp1T{V`10U1u48x@#kx#*2<~6xMcKa#SW%R z;Ugekuc?|rSAjceZ#?u<$x1FMSE) ztqL+g_3q0W8AkPQBu$BSh9r{`FPt3p4#n`v-}d|djjz`KuEumGc~rCqU* z15KDpVGg&a7;j4*eKFMfHHQ;BV>8wY{Sa-uyAE_sswtrr<~1>lb4r6}N;VZg&H{0| z<23T1+01D`tbPDURZSvqbQo@U9?DjK#+~MM0f)J^)g#Z(P_3Qbo}O|el2vaUEmf>^ z!>7$lXbdG2rZe6Q1QaTjAQATAXrS5&O}l7r1mD=|uK`_y$enqmfct=B+Ri*}aFu5t zbixr=D|W}qg;@keMINMDx~N4>RiXvWKVH*Q0mhg3NRHepq0l?ap3AArcqgpTzvVk# zKgm$oX&YA=}fMga8VS-g7xYcrX0Ia71{7br0>A>Yd zDS}iqY4n_(ra|bfS{SHy==P@lU(HSJ`rhPJw_2dvh33uF7Z=DfRit5mpvsc$$C+qa zE7UD1(P%~*6G|^>IZ-zzWrhr{z1T-D=++(S{Cfqa`^dNBL#!ddVtvuj#AJ-Q#D>-S%dNd9eda^{DPg2Ts7A-Su z(4z$Tir`{Pqf`lZbkaX{>5m@3MT*x>%%$M>Hc+_DLg&>CK!gO(Dru-=NesA6I)W(| zqzGief%x_4gtZuc?(P^D^qZa23wNSbj*Di|R!^K{MjxR)jI(O1O#LpDRk;thM3K1^ zT!xjVZJt*!ORJQ7%`vb7OYbP-DtB^b^K?u7XYjmlUQlbTThR+rq(0l_wE%?6QsS

8JBJ^BcPo9tcYY_-+;FR`o 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%0D0zneVCwv!K#s!8I3Lc7Cq7jT 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 X_#B`Aq|g5k00960RGnYK0OT_OxeJlN literal 0 HcmV?d00001 diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/_helpers.tpl b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/_helpers.tpl new file mode 100644 index 0000000000..146bc45a14 --- /dev/null +++ b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/_helpers.tpl @@ -0,0 +1,30 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/jobs.yaml b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/jobs.yaml new file mode 100644 index 0000000000..6955e3b309 --- /dev/null +++ b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/jobs.yaml @@ -0,0 +1,102 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Chart.Name }}-create + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Chart.Name }} + annotations: + "helm.sh/hook": post-install, post-upgrade, post-rollback + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed +spec: + template: + metadata: + name: {{ .Chart.Name }}-create + labels: + app: {{ .Chart.Name }} + spec: + serviceAccountName: {{ .Chart.Name }}-manager + securityContext: + runAsNonRoot: false + runAsUser: 0 + containers: + - name: create-crds + image: {{ template "system_default_registry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag }} + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - > + echo "Applying CRDs..."; + mkdir -p /etc/crd; + base64 -d /etc/config/crd-manifest.tgz.b64 | tar -xzv -C /etc/crd; + kubectl replace -Rf /etc/crd || kubectl create -Rf /etc/crd; + echo "Done!" + volumeMounts: + - name: crd-manifest + readOnly: true + mountPath: /etc/config + restartPolicy: OnFailure + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} + {{- if .Values.nodeSelector }} + {{- toYaml .Values.nodeSelector | nindent 8 }} + {{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} + {{- if .Values.tolerations }} + {{- toYaml .Values.tolerations | nindent 8 }} + {{- end }} + volumes: + - name: crd-manifest + configMap: + name: {{ .Chart.Name }}-manifest +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Chart.Name }}-delete + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Chart.Name }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed +spec: + template: + metadata: + name: {{ .Chart.Name }}-delete + labels: + app: {{ .Chart.Name }} + spec: + serviceAccountName: {{ .Chart.Name }}-manager + securityContext: + runAsNonRoot: false + runAsUser: 0 + containers: + - name: delete-crds + image: {{ template "system_default_registry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag }} + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - > + echo "Deleting CRDs..."; + mkdir -p /etc/crd; + base64 -d /etc/config/crd-manifest.tgz.b64 | tar -xzv -C /etc/crd; + kubectl delete --ignore-not-found=true -Rf /etc/crd; + volumeMounts: + - name: crd-manifest + readOnly: true + mountPath: /etc/config + restartPolicy: OnFailure + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} + {{- if .Values.nodeSelector }} + {{- toYaml .Values.nodeSelector | nindent 8 }} + {{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} + {{- if .Values.tolerations }} + {{- toYaml .Values.tolerations | nindent 8 }} + {{- end }} + volumes: + - name: crd-manifest + configMap: + name: {{ .Chart.Name }}-manifest diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/manifest.yaml b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/manifest.yaml new file mode 100644 index 0000000000..8dc9dfb447 --- /dev/null +++ b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/manifest.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Chart.Name }}-manifest + namespace: {{ .Release.Namespace }} +data: + crd-manifest.tgz.b64: + {{- .Files.Get "files/crd-manifest.tgz" | b64enc | indent 4 }} diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/rbac.yaml b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/rbac.yaml new file mode 100644 index 0000000000..a4d498b0fa --- /dev/null +++ b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/rbac.yaml @@ -0,0 +1,76 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ .Chart.Name }}-manager + labels: + app: {{ .Chart.Name }}-manager +rules: +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: ['create', 'get', 'patch', 'delete', 'update', 'list'] +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ .Chart.Name }}-manager +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Chart.Name }}-manager + labels: + app: {{ .Chart.Name }}-manager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Chart.Name }}-manager +subjects: +- kind: ServiceAccount + name: {{ .Chart.Name }}-manager + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Chart.Name }}-manager + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Chart.Name }}-manager +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ .Chart.Name }}-manager + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Chart.Name }}-manager +spec: + privileged: false + allowPrivilegeEscalation: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'configMap' + - 'secret' +{{- end }} diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/validate-psp-install.yaml b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring-crd/105.1.3+up61.3.2/values.yaml b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/values.yaml new file mode 100644 index 0000000000..99e63600c4 --- /dev/null +++ b/charts/rancher-monitoring-crd/105.1.3+up61.3.2/values.yaml @@ -0,0 +1,17 @@ +# Default values for rancher-monitoring-crd. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + +image: + repository: rancher/shell + tag: v0.2.1 + +nodeSelector: {} + +tolerations: [] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/.editorconfig b/charts/rancher-monitoring/105.1.3+up61.3.2/.editorconfig new file mode 100644 index 0000000000..f5ee2f4610 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[files/dashboards/*.json] +indent_size = 2 +indent_style = space \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/.helmignore new file mode 100644 index 0000000000..9bdbec92b4 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/.helmignore @@ -0,0 +1,29 @@ +# 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 +# helm/charts +OWNERS +hack/ +ci/ +kube-prometheus-*.tgz + +unittests/ +files/dashboards/ diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/CHANGELOG.md b/charts/rancher-monitoring/105.1.3+up61.3.2/CHANGELOG.md new file mode 100644 index 0000000000..8178169b91 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/CHANGELOG.md @@ -0,0 +1,47 @@ +# Changelog +All notable changes from the upstream Prometheus Operator chart will be added to this file. + +## [Package Version 00] - 2020-07-19 +### Added +- Added [Prometheus Adapter](https://github.com/helm/charts/tree/master/stable/prometheus-adapter) as a dependency to the upstream Prometheus Operator chart to allow users to expose custom metrics from the default Prometheus instance deployed by this chart +- Remove `prometheus-operator/cleanup-crds.yaml` and `prometheus-operator/crds.yaml` from the Prometheus Operator upstream chart in favor of just using the CRD directory to install the CRDs. +- Added support for `rkeControllerManager`, `rkeScheduler`, `rkeProxy`, and `rkeEtcd` PushProx exporters for monitoring k8s components within RKE clusters +- Added support for a `k3sServer` PushProx exporter that monitors k3s server components (`kubeControllerManager`, `kubeScheduler`, and `kubeProxy`) within k3s clusters +- Added support for `kubeAdmControllerManager`, `kubeAdmScheduler`, `kubeAdmProxy`, and `kubeAdmEtcd` PushProx exporters for monitoring k8s components within kubeAdm clusters +- Added support for `rke2ControllerManager`, `rke2Scheduler`, `rke2Proxy`, and `rke2Etcd` PushProx exporters for monitoring k8s components within rke2 clusters +- Exposed `prometheus.prometheusSpec.ignoreNamespaceSelectors` on values.yaml and set it to `false` by default. This value instructs the default Prometheus server deployed with this chart to ignore the `namespaceSelector` field within any created ServiceMonitor or PodMonitor CRs that it selects. This prevents ServiceMonitors and PodMonitors from configuring the Prometheus scrape configuration to monitor resources outside the namespace that they are deployed in; if a user needs to have one ServiceMonitor / PodMonitor monitor resources within several namespaces (such as the resources that are used to monitor Istio in a default installation), they should not enable this option since it would require them to create one ServiceMonitor / PodMonitor CR per namespace that they would like to monitor. Relevant fields were also updated in the default README.md. +- Added `grafana.sidecar.dashboards.searchNamespace` to `values.yaml` with a default value of `cattle-dashboards`. The namespace provided should contain all ConfigMaps with the label `grafana_dashboard` and will be searched by the Grafana Dashboards sidecar for updates. The namespace specified is also created along with this deployment. All default dashboard ConfigMaps have been relocated from the deployment namespace to the namespace specified +- Added `monitoring-admin`, `monitoring-edit`, and `monitoring-view` default `ClusterRoles` to allow admins to assign roles to users to interact with Prometheus Operator CRs. These can be enabled by setting `.Values.global.rbac.userRoles.create` (default: `true`). In a typical RBAC setup, you might want to use a `ClusterRoleBinding` to bind these roles to a Subject to allow them to set up or view `ServiceMonitors` / `PodMonitors` / `PrometheusRules` and view `Prometheus` or `Alertmanager` CRs across the cluster. If `.Values.global.rbac.userRoles.aggregateRolesForRBAC` is enabled, these ClusterRoles will aggregate into the respective default ClusterRoles provided by Kubernetes +- Added `monitoring-config-admin`, `monitoring-config-edit` and `monitoring-config-view` default `Roles` to allow admins to assign roles to users to be able to edit / view `Secrets` and `ConfigMaps` within the `cattle-monitoring-system` namespace. These can be enabled by setting `.Values.global.rbac.userRoles.create` (default: `true`). In a typical RBAC setup, you might want to use a `RoleBinding` to bind these roles to a Subject within the `cattle-monitoring-system` namespace to allow them to modify Secrets / ConfigMaps tied to the deployment, such as your Alertmanager Config Secret. +- Added `monitoring-dashboard-admin`, `monitoring-dashboard-edit` and `monitoring-dashboard-view` default `Roles` to allow admins to assign roles to users to be able to edit / view `ConfigMaps` within the `cattle-dashboards` namespace. These can be enabled by setting `.Values.global.rbac.userRoles.create` (default: `true`) and deploying Grafana as part of this chart. In a typical RBAC setup, you might want to use a `RoleBinding` to bind these roles to a Subject within the `cattle-dashboards` namespace to allow them to create / modify ConfigMaps that contain the JSON used to persist Grafana Dashboards on the cluster. +- Added default resource limits for `Prometheus Operator`, `Prometheus`, `AlertManager`, `Grafana`, `kube-state-metrics`, `node-exporter` +- Added a default template `rancher_defaults.tmpl` to AlertManager that Rancher will offer to users in order to help configure the way alerts are rendered on a notifier. Also updated the default template deployed with this chart to reference that template and added an example of a Slack config using this template as a comment in the `values.yaml`. +- Added support for private registries via introducing a new field for `global.cattle.systemDefaultRegistry` that, if supplied, will automatically be prepended onto every image used by the chart. +- Added a default `nginx` proxy container deployed with Grafana whose config is set in the `ConfigMap` located in `charts/grafana/templates/nginx-config.yaml`. The purpose of this container is to make it possible to view Grafana's UI through a proxy that has a subpath (e.g. Rancher's proxy). This proxy container is set to listen on port `8080` (with a `portName` of `nginx-http` instead of the default `service`), which is also where the Grafana service will now point to, and will forward all requests to the Grafana container listening on the default port `3000`. +- Added a default `nginx` proxy container deployed with Prometheus whose config is set in the `ConfigMap` located in `templates/prometheus/nginx-config.yaml`. The purpose of this container is to make it possible to view Prometheus's UI through a proxy that has a subpath (e.g. Rancher's proxy). This proxy container is set to listen on port `8081` (with a `portName` of `nginx-http` instead of the default `web`), which is also where the Prometheus service will now point to, and will forward all requests to the Prometheus container listening on the default port `9090`. +- Added support for passing CIS Scans in a hardened cluster by introducing a Job that patches the default service account within the `cattle-monitoring-system` and `cattle-dashboards` namespaces on install or upgrade and adding a default allow all `NetworkPolicy` to the `cattle-monitoring-system` and `cattle-dashboards` namespaces. +### Modified +- Updated the chart name from `prometheus-operator` to `rancher-monitoring` and added the `io.rancher.certified: rancher` annotation to `Chart.yaml` +- Modified the default `node-exporter` port from `9100` to `9796` +- Modified the default `nameOverride` to `rancher-monitoring`. This change is necessary as the Prometheus Adapter's default URL (`http://{{ .Values.nameOverride }}-prometheus.{{ .Values.namespaceOverride }}.svc`) is based off of the value used here; if modified, the default Adapter URL must also be modified +- Modified the default `namespaceOverride` to `cattle-monitoring-system`. This change is necessary as the Prometheus Adapter's default URL (`http://{{ .Values.nameOverride }}-prometheus.{{ .Values.namespaceOverride }}.svc`) is based off of the value used here; if modified, the default Adapter URL must also be modified +- Configured some default values for `grafana.service` values and exposed them in the default README.md +- The default namespaces the following ServiceMonitors were changed from the deployment namespace to allow them to continue to monitor metrics when `prometheus.prometheusSpec.ignoreNamespaceSelectors` is enabled: + - `core-dns`: `kube-system` + - `api-server`: `default` + - `kube-controller-manager`: `kube-system` + - `kubelet`: `{{ .Values.kubelet.namespace }}` +- Disabled the following deployments by default (can be enabled if required): + - `AlertManager` + - `kube-controller-manager` metrics exporter + - `kube-etcd` metrics exporter + - `kube-scheduler` metrics exporter + - `kube-proxy` metrics exporter +- Updated default Grafana `deploymentStrategy` to `Recreate` to prevent deployments from being stuck on upgrade if a PV is attached to Grafana +- Modified the default `SelectorNilUsesHelmValues` to default to `false`. As a result, we look for all CRs with any labels in all namespaces by default rather than just the ones tagged with the label `release: rancher-monitoring`. +- Modified the default images used by the `rancher-monitoring` chart to point to Rancher mirrors of the original images from upstream. +- Modified the behavior of the chart to create the Alertmanager Config Secret via a pre-install hook instead of using the normal Helm lifecycle to manage the secret. The benefit of this approach is that all changes to the Config Secret done on a live cluster will never get overridden on a `helm upgrade` since the secret only gets created on a `helm install`. If you would like the secret to be cleaned up on an `helm uninstall`, enable `alertmanager.cleanupOnUninstall`; however, this is disabled by default to prevent the loss of alerting configuration on an uninstall. This secret will never be modified on a `helm upgrade`. +- Modified the default `securityContext` for `Pod` templates across the chart to `{"runAsNonRoot": "true", "runAsUser": "1000"}` and replaced `grafana.rbac.pspUseAppArmor` in favor of `grafana.rbac.pspAnnotations={}` in order to make it possible to deploy this chart on a hardened cluster which does not support Seccomp or AppArmor annotations in PSPs. Users can always choose to specify the annotations they want to use for the PSP directly as part of the values provided. +- Modified `.Values.prometheus.prometheusSpec.containers` to take in a string representing a template that should be rendered by Helm (via `tpl`) instead of allowing a user to provide YAML directly. +- Modified the default Grafana configuration to auto assign users who access Grafana to the Viewer role and enable anonymous access to Grafana dashboards by default. This default works well for a Rancher user who is accessing Grafana via the `kubectl proxy` on the Rancher Dashboard UI since anonymous users who enter via the proxy are authenticated by the k8s API Server, but you can / should modify this behavior if you plan on exposing Grafana in a way that does not require authentication (e.g. as a `NodePort` service). +- Modified the default Grafana configuration to add a default dashboard for Rancher on the Grafana home page. \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/CONTRIBUTING.md b/charts/rancher-monitoring/105.1.3+up61.3.2/CONTRIBUTING.md new file mode 100644 index 0000000000..f6ce2a3235 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/CONTRIBUTING.md @@ -0,0 +1,12 @@ +# Contributing Guidelines + +## How to contribute to this chart + +1. Fork this repository, develop and test your Chart. +1. Bump the chart version for every change. +1. Ensure PR title has the prefix `[kube-prometheus-stack]` +1. When making changes to rules or dashboards, see the README.md section on how to sync data from upstream repositories +1. Check the `hack/minikube` folder has scripts to set up minikube and components of this chart that will allow all components to be scraped. You can use this configuration when validating your changes. +1. Check for changes of RBAC rules. +1. Check for changes in CRD specs. +1. PR must pass the linter (`helm lint`) diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/Chart.yaml new file mode 100644 index 0000000000..5ed6456ac2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/Chart.yaml @@ -0,0 +1,126 @@ +annotations: + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: Chart Source + url: https://github.com/prometheus-community/helm-charts + - name: Upstream Project + url: https://github.com/prometheus-operator/kube-prometheus + artifacthub.io/operator: "true" + catalog.cattle.io/auto-install: rancher-monitoring-crd=match + catalog.cattle.io/certified: rancher + catalog.cattle.io/deploys-on-os: windows + catalog.cattle.io/display-name: Monitoring + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/namespace: cattle-monitoring-system + catalog.cattle.io/permits-os: linux,windows + catalog.cattle.io/provides-gvr: monitoring.coreos.com.prometheus/v1 + catalog.cattle.io/rancher-version: '>= 2.10.0-0 < 2.11.0-0' + catalog.cattle.io/release-name: rancher-monitoring + catalog.cattle.io/requests-cpu: 4500m + catalog.cattle.io/requests-memory: 4000Mi + catalog.cattle.io/type: cluster-tool + catalog.cattle.io/ui-component: monitoring + catalog.cattle.io/upstream-version: 57.0.3 +apiVersion: v2 +appVersion: v0.75.1 +dependencies: +- condition: grafana.enabled + name: grafana + repository: file://./charts/grafana +- condition: hardenedKubelet.enabled + name: hardenedKubelet + repository: file://./charts/hardenedKubelet +- condition: hardenedNodeExporter.enabled + name: hardenedNodeExporter + repository: file://./charts/hardenedNodeExporter +- condition: k3sServer.enabled + name: k3sServer + repository: file://./charts/k3sServer +- condition: kubeStateMetrics.enabled + name: kube-state-metrics + repository: file://./charts/kube-state-metrics +- condition: kubeAdmControllerManager.enabled + name: kubeAdmControllerManager + repository: file://./charts/kubeAdmControllerManager +- condition: kubeAdmEtcd.enabled + name: kubeAdmEtcd + repository: file://./charts/kubeAdmEtcd +- condition: kubeAdmProxy.enabled + name: kubeAdmProxy + repository: file://./charts/kubeAdmProxy +- condition: kubeAdmScheduler.enabled + name: kubeAdmScheduler + repository: file://./charts/kubeAdmScheduler +- condition: prometheus-adapter.enabled + name: prometheus-adapter + repository: file://./charts/prometheus-adapter +- condition: nodeExporter.enabled + name: prometheus-node-exporter + repository: file://./charts/prometheus-node-exporter +- condition: rke2ControllerManager.enabled + name: rke2ControllerManager + repository: file://./charts/rke2ControllerManager +- condition: rke2Etcd.enabled + name: rke2Etcd + repository: file://./charts/rke2Etcd +- condition: rke2IngressNginx.enabled + name: rke2IngressNginx + repository: file://./charts/rke2IngressNginx +- condition: rke2Proxy.enabled + name: rke2Proxy + repository: file://./charts/rke2Proxy +- condition: rke2Scheduler.enabled + name: rke2Scheduler + repository: file://./charts/rke2Scheduler +- condition: rkeControllerManager.enabled + name: rkeControllerManager + repository: file://./charts/rkeControllerManager +- condition: rkeEtcd.enabled + name: rkeEtcd + repository: file://./charts/rkeEtcd +- condition: rkeIngressNginx.enabled + name: rkeIngressNginx + repository: file://./charts/rkeIngressNginx +- condition: rkeProxy.enabled + name: rkeProxy + repository: file://./charts/rkeProxy +- condition: rkeScheduler.enabled + name: rkeScheduler + repository: file://./charts/rkeScheduler +- condition: windowsExporter.enabled + name: windowsExporter + repository: file://./charts/windowsExporter +description: kube-prometheus-stack collects Kubernetes manifests, Grafana dashboards, + and Prometheus rules combined with documentation and scripts to provide easy to + operate end-to-end Kubernetes cluster monitoring with Prometheus using the Prometheus + Operator. +home: https://github.com/prometheus-operator/kube-prometheus +icon: file://assets/logos/rancher-monitoring.png +keywords: +- operator +- prometheus +- kube-prometheus +kubeVersion: '>=1.28.0-0' +maintainers: +- email: andrew@quadcorps.co.uk + name: andrewgkew +- email: gianrubio@gmail.com + name: gianrubio +- email: github.gkarthiks@gmail.com + name: gkarthiks +- email: kube-prometheus-stack@sisti.pt + name: GMartinez-Sisti +- email: github@jkroepke.de + name: jkroepke +- email: scott@r6by.com + name: scottrigby +- email: miroslav.hadzhiev@gmail.com + name: Xtigyro +- email: quentin.bisson@gmail.com + name: QuentinBisson +name: rancher-monitoring +sources: +- https://github.com/prometheus-community/helm-charts +- https://github.com/prometheus-operator/kube-prometheus +type: application +version: 105.1.3+up61.3.2 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/README.md new file mode 100644 index 0000000000..46f751587e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/README.md @@ -0,0 +1,1140 @@ +# kube-prometheus-stack + +Installs the [kube-prometheus stack](https://github.com/prometheus-operator/kube-prometheus), a collection of Kubernetes manifests, [Grafana](http://grafana.com/) dashboards, and [Prometheus rules](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/) combined with documentation and scripts to provide easy to operate end-to-end Kubernetes cluster monitoring with [Prometheus](https://prometheus.io/) using the [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator). + +See the [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus) README for details about components, dashboards, and alerts. + +_Note: This chart was formerly named `prometheus-operator` chart, now renamed to more clearly reflect that it installs the `kube-prometheus` project stack, within which Prometheus Operator is only one component._ + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3+ + +## Get Helm Repository Info + +```console +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update +``` + +_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Helm Chart + +```console +helm install [RELEASE_NAME] prometheus-community/kube-prometheus-stack +``` + +_See [configuration](#configuration) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Dependencies + +By default this chart installs additional, dependent charts: + +- [prometheus-community/kube-state-metrics](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics) +- [prometheus-community/prometheus-node-exporter](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-node-exporter) +- [grafana/grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana) + +To disable dependencies during installation, see [multiple releases](#multiple-releases) below. + +_See [helm dependency](https://helm.sh/docs/helm/helm_dependency/) for command documentation._ + +## Uninstall Helm Chart + +```console +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +CRDs created by this chart are not removed by default and should be manually cleaned up: + +```console +kubectl delete crd alertmanagerconfigs.monitoring.coreos.com +kubectl delete crd alertmanagers.monitoring.coreos.com +kubectl delete crd podmonitors.monitoring.coreos.com +kubectl delete crd probes.monitoring.coreos.com +kubectl delete crd prometheusagents.monitoring.coreos.com +kubectl delete crd prometheuses.monitoring.coreos.com +kubectl delete crd prometheusrules.monitoring.coreos.com +kubectl delete crd scrapeconfigs.monitoring.coreos.com +kubectl delete crd servicemonitors.monitoring.coreos.com +kubectl delete crd thanosrulers.monitoring.coreos.com +``` + +## Upgrading Chart + +```console +helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack +``` + +With Helm v3, CRDs created by this chart are not updated by default and should be manually updated. +Consult also the [Helm Documentation on CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions). + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### Upgrading an existing Release to a new major version + +A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an incompatible breaking change needing manual actions. + +### From 60.x to 61.x + +This version upgrades Prometheus-Operator to v0.75.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.75.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 59.x to 60.x + +This version upgrades the Grafana chart to v8.0.x which introduces Grafana 11. This new major version of Grafana contains some breaking changes described in [Breaking changes in Grafana v11.0](https://grafana.com/docs/grafana/latest/breaking-changes/breaking-changes-v11-0/). + +### From 58.x to 59.x + +This version upgrades Prometheus-Operator to v0.74.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 57.x to 58.x + +This version upgrades Prometheus-Operator to v0.73.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 56.x to 57.x + +This version upgrades Prometheus-Operator to v0.72.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 55.x to 56.x + +This version upgrades Prometheus-Operator to v0.71.0, Prometheus to 2.49.1 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 54.x to 55.x + +This version upgrades Prometheus-Operator to v0.70.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 53.x to 54.x + +Grafana Helm Chart has bumped to version 7 + +Please note Grafana Helm Chart [changelog](https://github.com/grafana/helm-charts/tree/main/charts/grafana#to-700). + +### From 52.x to 53.x + +This version upgrades Prometheus-Operator to v0.69.1, Prometheus to 2.47.2 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 51.x to 52.x + +This includes the ability to select between using existing secrets or create new secret objects for various thanos config. The defaults have not changed but if you were setting: + +- `thanosRuler.thanosRulerSpec.alertmanagersConfig` or +- `thanosRuler.thanosRulerSpec.objectStorageConfig` or +- `thanosRuler.thanosRulerSpec.queryConfig` or +- `prometheus.prometheusSpec.thanos.objectStorageConfig` + +you will have to need to set `existingSecret` or `secret` based on your requirement + +For instance, the `thanosRuler.thanosRulerSpec.alertmanagersConfig` used to be configured as follow: + +```yaml +thanosRuler: + thanosRulerSpec: + alertmanagersConfig: + alertmanagers: + - api_version: v2 + http_config: + basic_auth: + username: some_user + password: some_pass + static_configs: + - alertmanager.thanos.io + scheme: http + timeout: 10s +``` + +But it now moved to: + +```yaml +thanosRuler: + thanosRulerSpec: + alertmanagersConfig: + secret: + alertmanagers: + - api_version: v2 + http_config: + basic_auth: + username: some_user + password: some_pass + static_configs: + - alertmanager.thanos.io + scheme: http + timeout: 10s +``` + +or the `thanosRuler.thanosRulerSpec.objectStorageConfig` used to be configured as follow: + +```yaml +thanosRuler: + thanosRulerSpec: + objectStorageConfig: + name: existing-secret-not-created-by-this-chart + key: object-storage-configs.yaml +``` + +But it now moved to: + +```yaml +thanosRuler: + thanosRulerSpec: + objectStorageConfig: + existingSecret: + name: existing-secret-not-created-by-this-chart + key: object-storage-configs.yaml +``` + +### From 50.x to 51.x + +This version upgrades Prometheus-Operator to v0.68.0, Prometheus to 2.47.0 and Thanos to v0.32.2 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 49.x to 50.x + +This version requires Kubernetes 1.19+. + +We do not expect any breaking changes in this version. + +### From 48.x to 49.x + +This version upgrades Prometheus-Operator to v0.67.1, 0, Alertmanager to v0.26.0, Prometheus to 2.46.0 and Thanos to v0.32.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 47.x to 48.x + +This version moved all CRDs into a dedicated sub-chart. No new CRDs are introduced in this version. +See [#3548](https://github.com/prometheus-community/helm-charts/issues/3548) for more context. + +We do not expect any breaking changes in this version. + +### From 46.x to 47.x + +This version upgrades Prometheus-Operator to v0.66.0 with new CRDs (PrometheusAgent and ScrapeConfig). + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 45.x to 46.x + +This version upgrades Prometheus-Operator to v0.65.1 with new CRDs (PrometheusAgent and ScrapeConfig), Prometheus to v2.44.0 and Thanos to v0.31.0. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 44.x to 45.x + +This version upgrades Prometheus-Operator to v0.63.0, Prometheus to v2.42.0 and Thanos to v0.30.2. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 43.x to 44.x + +This version upgrades Prometheus-Operator to v0.62.0, Prometheus to v2.41.0 and Thanos to v0.30.1. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +If you have explicitly set `prometheusOperator.admissionWebhooks.failurePolicy`, this value is now always used even when `.prometheusOperator.admissionWebhooks.patch.enabled` is `true` (the default). + +The values for `prometheusOperator.image.tag` & `prometheusOperator.prometheusConfigReloader.image.tag` are now empty by default and the Chart.yaml `appVersion` field is used instead. + +### From 42.x to 43.x + +This version upgrades Prometheus-Operator to v0.61.1, Prometheus to v2.40.5 and Thanos to v0.29.0. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 41.x to 42.x + +This includes the overridability of container registry for all containers at the global level using `global.imageRegistry` or per container image. The defaults have not changed but if you were using a custom image, you will have to override the registry of said custom container image before you upgrade. + +For instance, the prometheus-config-reloader used to be configured as follow: + +```yaml + image: + repository: quay.io/prometheus-operator/prometheus-config-reloader + tag: v0.60.1 + sha: "" +``` + +But it now moved to: + +```yaml + image: + registry: quay.io + repository: prometheus-operator/prometheus-config-reloader + tag: v0.60.1 + sha: "" +``` + +### From 40.x to 41.x + +This version upgrades Prometheus-Operator to v0.60.1, Prometheus to v2.39.1 and Thanos to v0.28.1. +This version also upgrades the Helm charts of kube-state-metrics to 4.20.2, prometheus-node-exporter to 4.3.0 and Grafana to 6.40.4. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +This version splits kubeScheduler recording and altering rules in separate config values. +Instead of `defaultRules.rules.kubeScheduler` the 2 new variables `defaultRules.rules.kubeSchedulerAlerting` and `defaultRules.rules.kubeSchedulerRecording` are used. + +### From 39.x to 40.x + +This version upgrades Prometheus-Operator to v0.59.1, Prometheus to v2.38.0, kube-state-metrics to v2.6.0 and Thanos to v0.28.0. +This version also upgrades the Helm charts of kube-state-metrics to 4.18.0 and prometheus-node-exporter to 4.2.0. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +Starting from prometheus-node-exporter version 4.0.0, the `node exporter` chart is using the [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/). Therefore you have to delete the daemonset before you upgrade. + +```console +kubectl delete daemonset -l app=prometheus-node-exporter +helm upgrade -i kube-prometheus-stack prometheus-community/kube-prometheus-stack +``` + +If you use your own custom [ServiceMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor) or [PodMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#podmonitor), please ensure to upgrade their `selector` fields accordingly to the new labels. + +### From 38.x to 39.x + +This upgraded prometheus-operator to v0.58.0 and prometheus to v2.37.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 37.x to 38.x + +Reverted one of the default metrics relabelings for cAdvisor added in 36.x, due to it breaking container_network_* and various other statistics. If you do not want this change, you will need to override the `kubelet.cAdvisorMetricRelabelings`. + +### From 36.x to 37.x + +This includes some default metric relabelings for cAdvisor and apiserver metrics to reduce cardinality. If you do not want these defaults, you will need to override the `kubeApiServer.metricRelabelings` and or `kubelet.cAdvisorMetricRelabelings`. + +### From 35.x to 36.x + +This upgraded prometheus-operator to v0.57.0 and prometheus to v2.36.1 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 34.x to 35.x + +This upgraded prometheus-operator to v0.56.0 and prometheus to v2.35.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 33.x to 34.x + +This upgrades to prometheus-operator to v0.55.0 and prometheus to v2.33.5. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 32.x to 33.x + +This upgrades the prometheus-node-exporter Chart to v3.0.0. Please review the changes to this subchart if you make customizations to hostMountPropagation. + +### From 31.x to 32.x + +This upgrades to prometheus-operator to v0.54.0 and prometheus to v2.33.1. It also changes the default for `grafana.serviceMonitor.enabled` to `true. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 30.x to 31.x + +This version removes the built-in grafana ServiceMonitor and instead relies on the ServiceMonitor of the sub-chart. +`grafana.serviceMonitor.enabled` must be set instead of `grafana.serviceMonitor.selfMonitor` and the old ServiceMonitor may +need to be manually cleaned up after deploying the new release. + +### From 29.x to 30.x + +This version updates kube-state-metrics to 4.3.0 and uses the new option `kube-state-metrics.releaseLabel=true` which adds the "release" label to kube-state-metrics labels, making scraping of the metrics by kube-prometheus-stack work out of the box again, independent of the used kube-prometheus-stack release name. If you already set the "release" label via `kube-state-metrics.customLabels` you might have to remove that and use it via the new option. + +### From 28.x to 29.x + +This version makes scraping port for kube-controller-manager and kube-scheduler dynamic to reflect changes to default serving ports +for those components in Kubernetes versions v1.22 and v1.23 respectively. + +If you deploy on clusters using version v1.22+, kube-controller-manager will be scraped over HTTPS on port 10257. + +If you deploy on clusters running version v1.23+, kube-scheduler will be scraped over HTTPS on port 10259. + +### From 27.x to 28.x + +This version disables PodSecurityPolicies by default because they are deprecated in Kubernetes 1.21 and will be removed in Kubernetes 1.25. + +If you are using PodSecurityPolicies you can enable the previous behaviour by setting `kube-state-metrics.podSecurityPolicy.enabled`, `prometheus-node-exporter.rbac.pspEnabled`, `grafana.rbac.pspEnabled` and `global.rbac.pspEnabled` to `true`. + +### From 26.x to 27.x + +This version splits prometheus-node-exporter chart recording and altering rules in separate config values. +Instead of `defaultRules.rules.node` the 2 new variables `defaultRules.rules.nodeExporterAlerting` and `defaultRules.rules.nodeExporterRecording` are used. + +Also the following defaultRules.rules has been removed as they had no effect: `kubeApiserverError`, `kubePrometheusNodeAlerting`, `kubernetesAbsent`, `time`. + +The ability to set a rubookUrl via `defaultRules.rules.rubookUrl` was reintroduced. + +### From 25.x to 26.x + +This version enables the prometheus-node-exporter subchart servicemonitor by default again, by setting `prometheus-node-exporter.prometheus.monitor.enabled` to `true`. + +### From 24.x to 25.x + +This version upgrade to prometheus-operator v0.53.1. It removes support for setting a runbookUrl, since the upstream format for runbooks changed. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 23.x to 24.x + +The custom `ServiceMonitor` for the _kube-state-metrics_ & _prometheus-node-exporter_ charts have been removed in favour of the built-in sub-chart `ServiceMonitor`; for both sub-charts this means that `ServiceMonitor` customisations happen via the values passed to the chart. If you haven't directly customised this behaviour then there are no changes required to upgrade, but if you have please read the following. + +For _kube-state-metrics_ the `ServiceMonitor` customisation is now set via `kube-state-metrics.prometheus.monitor` and the `kubeStateMetrics.serviceMonitor.selfMonitor.enabled` value has moved to `kube-state-metrics.selfMonitor.enabled`. + +For _prometheus-node-exporter_ the `ServiceMonitor` customisation is now set via `prometheus-node-exporter.prometheus.monitor` and the `nodeExporter.jobLabel` values has moved to `prometheus-node-exporter.prometheus.monitor.jobLabel`. + +### From 22.x to 23.x + +Port names have been renamed for Istio's +[explicit protocol selection](https://istio.io/latest/docs/ops/configuration/traffic-management/protocol-selection/#explicit-protocol-selection). + +| | old value | new value | +|-|-----------|-----------| +| `alertmanager.alertmanagerSpec.portName` | `web` | `http-web` | +| `grafana.service.portName` | `service` | `http-web` | +| `prometheus-node-exporter.service.portName` | `metrics` (hardcoded) | `http-metrics` | +| `prometheus.prometheusSpec.portName` | `web` | `http-web` | + +### From 21.x to 22.x + +Due to the upgrade of the `kube-state-metrics` chart, removal of its deployment/stateful needs to done manually prior to upgrading: + +```console +kubectl delete deployments.apps -l app.kubernetes.io/instance=prometheus-operator,app.kubernetes.io/name=kube-state-metrics --cascade=orphan +``` + +or if you use autosharding: + +```console +kubectl delete statefulsets.apps -l app.kubernetes.io/instance=prometheus-operator,app.kubernetes.io/name=kube-state-metrics --cascade=orphan +``` + +### From 20.x to 21.x + +The config reloader values have been refactored. All the values have been moved to the key `prometheusConfigReloader` and the limits and requests can now be set separately. + +### From 19.x to 20.x + +Version 20 upgrades prometheus-operator from 0.50.x to 0.52.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 18.x to 19.x + +`kubeStateMetrics.serviceMonitor.namespaceOverride` was removed. +Please use `kube-state-metrics.namespaceOverride` instead. + +### From 17.x to 18.x + +Version 18 upgrades prometheus-operator from 0.49.x to 0.50.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 16.x to 17.x + +Version 17 upgrades prometheus-operator from 0.48.x to 0.49.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 15.x to 16.x + +Version 16 upgrades kube-state-metrics to v2.0.0. This includes changed command-line arguments and removed metrics, see this [blog post](https://kubernetes.io/blog/2021/04/13/kube-state-metrics-v-2-0/). This version also removes Grafana dashboards that supported Kubernetes 1.14 or earlier. + +### From 14.x to 15.x + +Version 15 upgrades prometheus-operator from 0.46.x to 0.47.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 13.x to 14.x + +Version 14 upgrades prometheus-operator from 0.45.x to 0.46.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 12.x to 13.x + +Version 13 upgrades prometheus-operator from 0.44.x to 0.45.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +``` + +### From 11.x to 12.x + +Version 12 upgrades prometheus-operator from 0.43.x to 0.44.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.44/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +``` + +The chart was migrated to support only helm v3 and later. + +### From 10.x to 11.x + +Version 11 upgrades prometheus-operator from 0.42.x to 0.43.x. Starting with 0.43.x an additional `AlertmanagerConfigs` CRD is introduced. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.43/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +``` + +Version 11 removes the deprecated tlsProxy via ghostunnel in favor of native TLS support the prometheus-operator gained with v0.39.0. + +### From 9.x to 10.x + +Version 10 upgrades prometheus-operator from 0.38.x to 0.42.x. Starting with 0.40.x an additional `Probes` CRD is introduced. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.42/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +``` + +### From 8.x to 9.x + +Version 9 of the helm chart removes the existing `additionalScrapeConfigsExternal` in favour of `additionalScrapeConfigsSecret`. This change lets users specify the secret name and secret key to use for the additional scrape configuration of prometheus. This is useful for users that have prometheus-operator as a subchart and also have a template that creates the additional scrape configuration. + +### From 7.x to 8.x + +Due to new template functions being used in the rules in version 8.x.x of the chart, an upgrade to Prometheus Operator and Prometheus is necessary in order to support them. First, upgrade to the latest version of 7.x.x + +```console +helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack --version 7.5.0 +``` + +Then upgrade to 8.x.x + +```console +helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack --version [8.x.x] +``` + +Minimal recommended Prometheus version for this chart release is `2.12.x` + +### From 6.x to 7.x + +Due to a change in grafana subchart, version 7.x.x now requires Helm >= 2.12.0. + +### From 5.x to 6.x + +Due to a change in deployment labels of kube-state-metrics, the upgrade requires `helm upgrade --force` in order to re-create the deployment. If this is not done an error will occur indicating that the deployment cannot be modified: + +```console +invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{"app.kubernetes.io/name":"kube-state-metrics"}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable +``` + +If this error has already been encountered, a `helm history` command can be used to determine which release has worked, then `helm rollback` to the release, then `helm upgrade --force` to this new one + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments: + +```console +helm show values prometheus-community/kube-prometheus-stack +``` + +You may also run `helm show values` on this chart's [dependencies](#dependencies) for additional options. + +### Rancher Monitoring Configuration + +The following table shows values exposed by Rancher Monitoring's additions to the chart: + +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `nameOverride` | Provide a name that should be used instead of the chart name when naming all resources deployed by this chart |`"rancher-monitoring"`| +| `namespaceOverride` | Override the deployment namespace | `"cattle-monitoring-system"` | +| `global.rbac.userRoles.create` | Create default user ClusterRoles to allow users to interact with Prometheus CRs, ConfigMaps, and Secrets | `true` | +| `global.rbac.userRoles.aggregateToDefaultRoles` | Aggregate default user ClusterRoles into default k8s ClusterRoles | `true` | +| `prometheus-adapter.enabled` | Whether to install [prometheus-adapter](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-adapter) within the cluster | `true` | +| `prometheus-adapter.prometheus.url` | A URL pointing to the Prometheus deployment within your cluster. The default value is set based on the assumption that you plan to deploy the default Prometheus instance from this chart where `.Values.namespaceOverride=cattle-monitoring-system` and `.Values.nameOverride=rancher-monitoring` | `http://rancher-monitoring-prometheus.cattle-monitoring-system.svc` | +| `prometheus-adapter.prometheus.port` | The port on the Prometheus deployment that Prometheus Adapter can make requests to | `9090` | +| `prometheus.prometheusSpec.ignoreNamespaceSelectors` | Ignore NamespaceSelector settings from the PodMonitor and ServiceMonitor configs. If true, PodMonitors and ServiceMonitors can only discover Pods and Services within the namespace they are deployed into | `false` | + +The following values are enabled for different distributions via [rancher-pushprox](https://github.com/rancher/dev-charts/tree/master/packages/rancher-pushprox). See the rancher-pushprox `README.md` for more information on what all values can be configured for the PushProxy chart. + +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `rkeControllerManager.enabled` | Create a PushProx installation for monitoring kube-controller-manager metrics in RKE clusters | `false` | +| `rkeScheduler.enabled` | Create a PushProx installation for monitoring kube-scheduler metrics in RKE clusters | `false` | +| `rkeProxy.enabled` | Create a PushProx installation for monitoring kube-proxy metrics in RKE clusters | `false` | +| `rkeIngressNginx.enabled` | Create a PushProx installation for monitoring ingress-nginx metrics in RKE clusters | `false` | +| `rkeEtcd.enabled` | Create a PushProx installation for monitoring etcd metrics in RKE clusters | `false` | +| `rke2IngressNginx.enabled` | Create a PushProx installation for monitoring ingress-nginx metrics in RKE2 clusters | `false` | +| `k3sServer.enabled` | Create a PushProx installation for monitoring k3s-server metrics (accounts for kube-controller-manager, kube-scheduler, and kube-proxy metrics) in k3s clusters | `false` | +| `kubeAdmControllerManager.enabled` | Create a PushProx installation for monitoring kube-controller-manager metrics in kubeAdm clusters | `false` | +| `kubeAdmScheduler.enabled` | Create a PushProx installation for monitoring kube-scheduler metrics in kubeAdm clusters | `false` | +| `kubeAdmProxy.enabled` | Create a PushProx installation for monitoring kube-proxy metrics in kubeAdm clusters | `false` | +| `kubeAdmEtcd.enabled` | Create a PushProx installation for monitoring etcd metrics in kubeAdm clusters | `false` | + +### Multiple releases + +The same chart can be used to run multiple Prometheus instances in the same cluster if required. To achieve this, it is necessary to run only one instance of prometheus-operator and a pair of alertmanager pods for an HA configuration, while all other components need to be disabled. To disable a dependency during installation, set `kubeStateMetrics.enabled`, `nodeExporter.enabled` and `grafana.enabled` to `false`. + +## Work-Arounds for Known Issues + +### Running on private GKE clusters + +When Google configure the control plane for private clusters, they automatically configure VPC peering between your Kubernetes cluster’s network and a separate Google managed project. In order to restrict what Google are able to access within your cluster, the firewall rules configured restrict access to your Kubernetes pods. This means that in order to use the webhook component with a GKE private cluster, you must configure an additional firewall rule to allow the GKE control plane access to your webhook pod. + +You can read more information on how to add firewall rules for the GKE control plane nodes in the [GKE docs](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#add_firewall_rules) + +Alternatively, you can disable the hooks by setting `prometheusOperator.admissionWebhooks.enabled=false`. + +## PrometheusRules Admission Webhooks + +With Prometheus Operator version 0.30+, the core Prometheus Operator pod exposes an endpoint that will integrate with the `validatingwebhookconfiguration` Kubernetes feature to prevent malformed rules from being added to the cluster. + +### How the Chart Configures the Hooks + +A validating and mutating webhook configuration requires the endpoint to which the request is sent to use TLS. It is possible to set up custom certificates to do this, but in most cases, a self-signed certificate is enough. The setup of this component requires some more complex orchestration when using helm. The steps are created to be idempotent and to allow turning the feature on and off without running into helm quirks. + +1. A pre-install hook provisions a certificate into the same namespace using a format compatible with provisioning using end user certificates. If the certificate already exists, the hook exits. +2. The prometheus operator pod is configured to use a TLS proxy container, which will load that certificate. +3. Validating and Mutating webhook configurations are created in the cluster, with their failure mode set to Ignore. This allows rules to be created by the same chart at the same time, even though the webhook has not yet been fully set up - it does not have the correct CA field set. +4. A post-install hook reads the CA from the secret created by step 1 and patches the Validating and Mutating webhook configurations. This process will allow a custom CA provisioned by some other process to also be patched into the webhook configurations. The chosen failure policy is also patched into the webhook configurations + +### Alternatives + +It should be possible to use [jetstack/cert-manager](https://github.com/jetstack/cert-manager) if a more complete solution is required, but it has not been tested. + +You can enable automatic self-signed TLS certificate provisioning via cert-manager by setting the `prometheusOperator.admissionWebhooks.certManager.enabled` value to true. + +### Limitations + +Because the operator can only run as a single pod, there is potential for this component failure to cause rule deployment failure. Because this risk is outweighed by the benefit of having validation, the feature is enabled by default. + +## Developing Prometheus Rules and Grafana Dashboards + +This chart Grafana Dashboards and Prometheus Rules are just a copy from [prometheus-operator/prometheus-operator](https://github.com/prometheus-operator/prometheus-operator) and other sources, synced (with alterations) by scripts in [hack](hack) folder. In order to introduce any changes you need to first [add them to the original repository](https://github.com/prometheus-operator/kube-prometheus/blob/main/docs/customizations/developing-prometheus-rules-and-grafana-dashboards.md) and then sync there by scripts. + +## Further Information + +For more in-depth documentation of configuration options meanings, please see + +- [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator) +- [Prometheus](https://prometheus.io/docs/introduction/overview/) +- [Grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana#grafana-helm-chart) + +## prometheus.io/scrape + +The prometheus operator does not support annotation-based discovery of services, using the `PodMonitor` or `ServiceMonitor` CRD in its place as they provide far more configuration options. +For information on how to use PodMonitors/ServiceMonitors, please see the documentation on the `prometheus-operator/prometheus-operator` documentation here: + +- [ServiceMonitors](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md#include-servicemonitors) +- [PodMonitors](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md#include-podmonitors) +- [Running Exporters](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/running-exporters.md) + +By default, Prometheus discovers PodMonitors and ServiceMonitors within its namespace, that are labeled with the same release tag as the prometheus-operator release. +Sometimes, you may need to discover custom PodMonitors/ServiceMonitors, for example used to scrape data from third-party applications. +An easy way of doing this, without compromising the default PodMonitors/ServiceMonitors discovery, is allowing Prometheus to discover all PodMonitors/ServiceMonitors within its namespace, without applying label filtering. +To do so, you can set `prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues` and `prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues` to `false`. + +## Migrating from stable/prometheus-operator chart + +## Zero downtime + +Since `kube-prometheus-stack` is fully compatible with the `stable/prometheus-operator` chart, a migration without downtime can be achieved. +However, the old name prefix needs to be kept. If you want the new name please follow the step by step guide below (with downtime). + +You can override the name to achieve this: + +```console +helm upgrade prometheus-operator prometheus-community/kube-prometheus-stack -n monitoring --reuse-values --set nameOverride=prometheus-operator +``` + +**Note**: It is recommended to run this first with `--dry-run --debug`. + +## Redeploy with new name (downtime) + +If the **prometheus-operator** values are compatible with the new **kube-prometheus-stack** chart, please follow the below steps for migration: + +> The guide presumes that chart is deployed in `monitoring` namespace and the deployments are running there. If in other namespace, please replace the `monitoring` to the deployed namespace. + +1. Patch the PersistenceVolume created/used by the prometheus-operator chart to `Retain` claim policy: + + ```console + kubectl patch pv/ -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' + ``` + + **Note:** To execute the above command, the user must have a cluster wide permission. Please refer [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) + +2. Uninstall the **prometheus-operator** release and delete the existing PersistentVolumeClaim, and verify PV become Released. + + ```console + helm uninstall prometheus-operator -n monitoring + kubectl delete pvc/ -n monitoring + ``` + + Additionally, you have to manually remove the remaining `prometheus-operator-kubelet` service. + + ```console + kubectl delete service/prometheus-operator-kubelet -n kube-system + ``` + + You can choose to remove all your existing CRDs (ServiceMonitors, Podmonitors, etc.) if you want to. + +3. Remove current `spec.claimRef` values to change the PV's status from Released to Available. + + ```console + kubectl patch pv/ --type json -p='[{"op": "remove", "path": "/spec/claimRef"}]' -n monitoring + ``` + +**Note:** To execute the above command, the user must have a cluster wide permission. Please refer to [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) + +After these steps, proceed to a fresh **kube-prometheus-stack** installation and make sure the current release of **kube-prometheus-stack** matching the `volumeClaimTemplate` values in the `values.yaml`. + +The binding is done via matching a specific amount of storage requested and with certain access modes. + +For example, if you had storage specified as this with **prometheus-operator**: + +```yaml +volumeClaimTemplate: + spec: + storageClassName: gp2 + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 50Gi +``` + +You have to specify matching `volumeClaimTemplate` with 50Gi storage and `ReadWriteOnce` access mode. + +Additionally, you should check the current AZ of your legacy installation's PV, and configure the fresh release to use the same AZ as the old one. If the pods are in a different AZ than the PV, the release will fail to bind the existing one, hence creating a new PV. + +This can be achieved either by specifying the labels through `values.yaml`, e.g. setting `prometheus.prometheusSpec.nodeSelector` to: + +```yaml +nodeSelector: + failure-domain.beta.kubernetes.io/zone: east-west-1a +``` + +or passing these values as `--set` overrides during installation. + +The new release should now re-attach your previously released PV with its content. + +## Migrating from coreos/prometheus-operator chart + +The multiple charts have been combined into a single chart that installs prometheus operator, prometheus, alertmanager, grafana as well as the multitude of exporters necessary to monitor a cluster. + +There is no simple and direct migration path between the charts as the changes are extensive and intended to make the chart easier to support. + +The capabilities of the old chart are all available in the new chart, including the ability to run multiple prometheus instances on a single cluster - you will need to disable the parts of the chart you do not wish to deploy. + +You can check out the tickets for this change [here](https://github.com/prometheus-operator/prometheus-operator/issues/592) and [here](https://github.com/helm/charts/pull/6765). + +### High-level overview of Changes + +#### Added dependencies + +The chart has added 3 [dependencies](#dependencies). + +- Node-Exporter, Kube-State-Metrics: These components are loaded as dependencies into the chart, and are relatively simple components +- Grafana: The Grafana chart is more feature-rich than this chart - it contains a sidecar that is able to load data sources and dashboards from configmaps deployed into the same cluster. For more information check out the [documentation for the chart](https://github.com/grafana/helm-charts/blob/main/charts/grafana/README.md) + +#### Kubelet Service + +Because the kubelet service has a new name in the chart, make sure to clean up the old kubelet service in the `kube-system` namespace to prevent counting container metrics twice. + +#### Persistent Volumes + +If you would like to keep the data of the current persistent volumes, it should be possible to attach existing volumes to new PVCs and PVs that are created using the conventions in the new chart. For example, in order to use an existing Azure disk for a helm release called `prometheus-migration` the following resources can be created: + +```yaml +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pvc-prometheus-migration-prometheus-0 +spec: + accessModes: + - ReadWriteOnce + azureDisk: + cachingMode: None + diskName: pvc-prometheus-migration-prometheus-0 + diskURI: /subscriptions/f5125d82-2622-4c50-8d25-3f7ba3e9ac4b/resourceGroups/sample-migration-resource-group/providers/Microsoft.Compute/disks/pvc-prometheus-migration-prometheus-0 + fsType: "" + kind: Managed + readOnly: false + capacity: + storage: 1Gi + persistentVolumeReclaimPolicy: Delete + storageClassName: prometheus + volumeMode: Filesystem +``` + +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: prometheus + prometheus: prometheus-migration-prometheus + name: prometheus-prometheus-migration-prometheus-db-prometheus-prometheus-migration-prometheus-0 + namespace: monitoring +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + storageClassName: prometheus + volumeMode: Filesystem + volumeName: pvc-prometheus-migration-prometheus-0 +``` + +The PVC will take ownership of the PV and when you create a release using a persistent volume claim template it will use the existing PVCs as they match the naming convention used by the chart. For other cloud providers similar approaches can be used. + +#### KubeProxy + +The metrics bind address of kube-proxy is default to `127.0.0.1:10249` that prometheus instances **cannot** access to. You should expose metrics by changing `metricsBindAddress` field value to `0.0.0.0:10249` if you want to collect them. + +Depending on the cluster, the relevant part `config.conf` will be in ConfigMap `kube-system/kube-proxy` or `kube-system/kube-proxy-config`. For example: + +```console +kubectl -n kube-system edit cm kube-proxy +``` + +```yaml +apiVersion: v1 +data: + config.conf: |- + apiVersion: kubeproxy.config.k8s.io/v1alpha1 + kind: KubeProxyConfiguration + # ... + # metricsBindAddress: 127.0.0.1:10249 + metricsBindAddress: 0.0.0.0:10249 + # ... + kubeconfig.conf: |- + # ... +kind: ConfigMap +metadata: + labels: + app: kube-proxy + name: kube-proxy + namespace: kube-system +``` diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/app-README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/app-README.md new file mode 100644 index 0000000000..3920854384 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/app-README.md @@ -0,0 +1,46 @@ +# Rancher Monitoring and Alerting + + This chart is based on the upstream [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) chart. The chart deploys [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator) and its CRDs along with [Grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana), [Prometheus Adapter](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-adapter) and additional charts / Kubernetes manifests to gather metrics. It allows users to monitor their Kubernetes clusters, view metrics in Grafana dashboards, and set up alerts and notifications. + +For more information on how to use the feature, refer to our [docs](https://rancher.com/docs/rancher/v2.x/en/monitoring-alerting/v2.5/). + +The chart installs the following components: + +- [Prometheus Operator](https://github.com/coreos/prometheus-operator) - The operator provides easy monitoring definitions for Kubernetes services, manages [Prometheus](https://prometheus.io/) and [AlertManager](https://prometheus.io/docs/alerting/latest/alertmanager/) instances, and adds default scrape targets for some Kubernetes components. +- [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus/) - A collection of community-curated Kubernetes manifests, Grafana Dashboards, and PrometheusRules that deploy a default end-to-end cluster monitoring configuration. +- [Grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana) - Grafana allows a user to create / view dashboards based on the cluster metrics collected by Prometheus. +- [node-exporter](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-node-exporter) / [kube-state-metrics](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics) / [rancher-pushprox](https://github.com/rancher/charts/tree/dev-v2.7/packages/rancher-monitoring/rancher-pushprox/charts) - These charts monitor various Kubernetes components across different Kubernetes cluster types. +- [Prometheus Adapter](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-adapter) - The adapter allows a user to expose custom metrics, resource metrics, and external metrics on the default [Prometheus](https://prometheus.io/) instance to the Kubernetes API Server. + +For more information, review the Helm README of this chart. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. +​ +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Upgrading from 100.0.0+up16.6.0 to 100.1.0+up19.0.3 + +### Noticeable changes: +Grafana: +- `sidecar.dashboards.searchNamespace`, `sidecar.datasources.searchNamespace` and `sidecar.notifiers.searchNamespace` support a list of namespaces now. + +Kube-state-metrics +- the type of `collectors` is changed from Dictionary to List. +- `kubeStateMetrics.serviceMonitor.namespaceOverride` was replaced by `kube-state-metrics.namespaceOverride`. + +### Known issues: +- Occasionally, the upgrade fails with errors related to the webhook `prometheusrulemutate.monitoring.coreos.com`. This is a known issue in the upstream, and the workaround is to trigger the upgrade one more time. [32416](https://github.com/rancher/rancher/issues/32416#issuecomment-828881726) diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/.helmignore new file mode 100644 index 0000000000..8cade1318f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/.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 +*~ +# Various IDEs +.vscode +.project +.idea/ +*.tmproj +OWNERS diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/Chart.yaml new file mode 100644 index 0000000000..7770ebbe5a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/Chart.yaml @@ -0,0 +1,41 @@ +annotations: + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: Chart Source + url: https://github.com/grafana/helm-charts + - name: Upstream Project + url: https://github.com/grafana/grafana + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-grafana +apiVersion: v2 +appVersion: 11.1.0 +description: The leading tool for querying and visualizing time series and metrics. +home: https://grafana.com +icon: https://artifacthub.io/image/b4fed1a7-6c8f-4945-b99d-096efa3e4116 +keywords: +- monitoring +- metric +kubeVersion: '>=1.28.0-0' +maintainers: +- email: zanhsieh@gmail.com + name: zanhsieh +- email: rluckie@cisco.com + name: rtluckie +- email: maor.friedman@redhat.com + name: maorfr +- email: miroslav.hadzhiev@gmail.com + name: Xtigyro +- email: mail@torstenwalter.de + name: torstenwalter +- email: github@jkroepke.de + name: jkroepke +name: grafana +sources: +- https://github.com/grafana/grafana +- https://github.com/grafana/helm-charts +type: application +version: 8.3.6 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/README.md new file mode 100644 index 0000000000..f758963a4b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/README.md @@ -0,0 +1,778 @@ +# Grafana Helm Chart + +* Installs the web dashboarding system [Grafana](http://grafana.org/) + +## Get Repo Info + +```console +helm repo add grafana https://grafana.github.io/helm-charts +helm repo update +``` + +_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Installing the Chart + +To install the chart with the release name `my-release`: + +```console +helm install my-release grafana/grafana +``` + +## Uninstalling the Chart + +To uninstall/delete the my-release deployment: + +```console +helm delete my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +## Upgrading an existing Release to a new major version + +A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an +incompatible breaking change needing manual actions. + +### To 4.0.0 (And 3.12.1) + +This version requires Helm >= 2.12.0. + +### To 5.0.0 + +You have to add --force to your helm upgrade command as the labels of the chart have changed. + +### To 6.0.0 + +This version requires Helm >= 3.1.0. + +### To 7.0.0 + +For consistency with other Helm charts, the `global.image.registry` parameter was renamed +to `global.imageRegistry`. If you were not previously setting `global.image.registry`, no action +is required on upgrade. If you were previously setting `global.image.registry`, you will +need to instead set `global.imageRegistry`. + +## Configuration + +| Parameter | Description | Default | +|-------------------------------------------|-----------------------------------------------|---------------------------------------------------------| +| `replicas` | Number of nodes | `1` | +| `podDisruptionBudget.minAvailable` | Pod disruption minimum available | `nil` | +| `podDisruptionBudget.maxUnavailable` | Pod disruption maximum unavailable | `nil` | +| `podDisruptionBudget.apiVersion` | Pod disruption apiVersion | `nil` | +| `deploymentStrategy` | Deployment strategy | `{ "type": "RollingUpdate" }` | +| `livenessProbe` | Liveness Probe settings | `{ "httpGet": { "path": "/api/health", "port": 3000 } "initialDelaySeconds": 60, "timeoutSeconds": 30, "failureThreshold": 10 }` | +| `readinessProbe` | Readiness Probe settings | `{ "httpGet": { "path": "/api/health", "port": 3000 } }`| +| `securityContext` | Deployment securityContext | `{"runAsUser": 472, "runAsGroup": 472, "fsGroup": 472}` | +| `priorityClassName` | Name of Priority Class to assign pods | `nil` | +| `image.registry` | Image registry | `docker.io` | +| `image.repository` | Image repository | `grafana/grafana` | +| `image.tag` | Overrides the Grafana image tag whose default is the chart appVersion (`Must be >= 5.0.0`) | `` | +| `image.sha` | Image sha (optional) | `` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `image.pullSecrets` | Image pull secrets (can be templated) | `[]` | +| `service.enabled` | Enable grafana service | `true` | +| `service.ipFamilies` | Kubernetes service IP families | `[]` | +| `service.ipFamilyPolicy` | Kubernetes service IP family policy | `""` | +| `service.type` | Kubernetes service type | `ClusterIP` | +| `service.port` | Kubernetes port where service is exposed | `80` | +| `service.portName` | Name of the port on the service | `service` | +| `service.appProtocol` | Adds the appProtocol field to the service | `` | +| `service.targetPort` | Internal service is port | `3000` | +| `service.nodePort` | Kubernetes service nodePort | `nil` | +| `service.annotations` | Service annotations (can be templated) | `{}` | +| `service.labels` | Custom labels | `{}` | +| `service.clusterIP` | internal cluster service IP | `nil` | +| `service.loadBalancerIP` | IP address to assign to load balancer (if supported) | `nil` | +| `service.loadBalancerSourceRanges` | list of IP CIDRs allowed access to lb (if supported) | `[]` | +| `service.externalIPs` | service external IP addresses | `[]` | +| `service.externalTrafficPolicy` | change the default externalTrafficPolicy | `nil` | +| `headlessService` | Create a headless service | `false` | +| `extraExposePorts` | Additional service ports for sidecar containers| `[]` | +| `hostAliases` | adds rules to the pod's /etc/hosts | `[]` | +| `ingress.enabled` | Enables Ingress | `false` | +| `ingress.annotations` | Ingress annotations (values are templated) | `{}` | +| `ingress.labels` | Custom labels | `{}` | +| `ingress.path` | Ingress accepted path | `/` | +| `ingress.pathType` | Ingress type of path | `Prefix` | +| `ingress.hosts` | Ingress accepted hostnames | `["chart-example.local"]` | +| `ingress.extraPaths` | Ingress extra paths to prepend to every host configuration. Useful when configuring [custom actions with AWS ALB Ingress Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.6/guide/ingress/annotations/#actions). Requires `ingress.hosts` to have one or more host entries. | `[]` | +| `ingress.tls` | Ingress TLS configuration | `[]` | +| `ingress.ingressClassName` | Ingress Class Name. MAY be required for Kubernetes versions >= 1.18 | `""` | +| `resources` | CPU/Memory resource requests/limits | `{}` | +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Toleration labels for pod assignment | `[]` | +| `affinity` | Affinity settings for pod assignment | `{}` | +| `extraInitContainers` | Init containers to add to the grafana pod | `{}` | +| `extraContainers` | Sidecar containers to add to the grafana pod | `""` | +| `extraContainerVolumes` | Volumes that can be mounted in sidecar containers | `[]` | +| `extraLabels` | Custom labels for all manifests | `{}` | +| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | +| `persistence.enabled` | Use persistent volume to store data | `false` | +| `persistence.type` | Type of persistence (`pvc` or `statefulset`) | `pvc` | +| `persistence.size` | Size of persistent volume claim | `10Gi` | +| `persistence.existingClaim` | Use an existing PVC to persist data (can be templated) | `nil` | +| `persistence.storageClassName` | Type of persistent volume claim | `nil` | +| `persistence.accessModes` | Persistence access modes | `[ReadWriteOnce]` | +| `persistence.annotations` | PersistentVolumeClaim annotations | `{}` | +| `persistence.finalizers` | PersistentVolumeClaim finalizers | `[ "kubernetes.io/pvc-protection" ]` | +| `persistence.extraPvcLabels` | Extra labels to apply to a PVC. | `{}` | +| `persistence.subPath` | Mount a sub dir of the persistent volume (can be templated) | `nil` | +| `persistence.inMemory.enabled` | If persistence is not enabled, whether to mount the local storage in-memory to improve performance | `false` | +| `persistence.inMemory.sizeLimit` | SizeLimit for the in-memory local storage | `nil` | +| `persistence.disableWarning` | Hide NOTES warning, useful when persiting to a database | `false` | +| `initChownData.enabled` | If false, don't reset data ownership at startup | true | +| `initChownData.image.registry` | init-chown-data container image registry | `docker.io` | +| `initChownData.image.repository` | init-chown-data container image repository | `busybox` | +| `initChownData.image.tag` | init-chown-data container image tag | `1.31.1` | +| `initChownData.image.sha` | init-chown-data container image sha (optional)| `""` | +| `initChownData.image.pullPolicy` | init-chown-data container image pull policy | `IfNotPresent` | +| `initChownData.resources` | init-chown-data pod resource requests & limits | `{}` | +| `schedulerName` | Alternate scheduler name | `nil` | +| `env` | Extra environment variables passed to pods | `{}` | +| `envValueFrom` | Environment variables from alternate sources. See the API docs on [EnvVarSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#envvarsource-v1-core) for format details. Can be templated | `{}` | +| `envFromSecret` | Name of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `""` | +| `envFromSecrets` | List of Kubernetes secrets (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `[]` | +| `envFromConfigMaps` | List of Kubernetes ConfigMaps (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `[]` | +| `envRenderSecret` | Sensible environment variables passed to pods and stored as secret. (passed through [tpl](https://helm.sh/docs/howto/charts_tips_and_tricks/#using-the-tpl-function)) | `{}` | +| `enableServiceLinks` | Inject Kubernetes services as environment variables. | `true` | +| `extraSecretMounts` | Additional grafana server secret mounts | `[]` | +| `extraVolumeMounts` | Additional grafana server volume mounts | `[]` | +| `extraVolumes` | Additional Grafana server volumes | `[]` | +| `automountServiceAccountToken` | Mounted the service account token on the grafana pod. Mandatory, if sidecars are enabled | `true` | +| `createConfigmap` | Enable creating the grafana configmap | `true` | +| `extraConfigmapMounts` | Additional grafana server configMap volume mounts (values are templated) | `[]` | +| `extraEmptyDirMounts` | Additional grafana server emptyDir volume mounts | `[]` | +| `plugins` | Plugins to be loaded along with Grafana | `[]` | +| `datasources` | Configure grafana datasources (passed through tpl) | `{}` | +| `alerting` | Configure grafana alerting (passed through tpl) | `{}` | +| `notifiers` | Configure grafana notifiers | `{}` | +| `dashboardProviders` | Configure grafana dashboard providers | `{}` | +| `dashboards` | Dashboards to import | `{}` | +| `dashboardsConfigMaps` | ConfigMaps reference that contains dashboards | `{}` | +| `grafana.ini` | Grafana's primary configuration | `{}` | +| `global.imageRegistry` | Global image pull registry for all images. | `null` | +| `global.imagePullSecrets` | Global image pull secrets (can be templated). Allows either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style). | `[]` | +| `ldap.enabled` | Enable LDAP authentication | `false` | +| `ldap.existingSecret` | The name of an existing secret containing the `ldap.toml` file, this must have the key `ldap-toml`. | `""` | +| `ldap.config` | Grafana's LDAP configuration | `""` | +| `annotations` | Deployment annotations | `{}` | +| `labels` | Deployment labels | `{}` | +| `podAnnotations` | Pod annotations | `{}` | +| `podLabels` | Pod labels | `{}` | +| `podPortName` | Name of the grafana port on the pod | `grafana` | +| `lifecycleHooks` | Lifecycle hooks for podStart and preStop [Example](https://kubernetes.io/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/#define-poststart-and-prestop-handlers) | `{}` | +| `sidecar.image.registry` | Sidecar image registry | `quay.io` | +| `sidecar.image.repository` | Sidecar image repository | `kiwigrid/k8s-sidecar` | +| `sidecar.image.tag` | Sidecar image tag | `1.26.0` | +| `sidecar.image.sha` | Sidecar image sha (optional) | `""` | +| `sidecar.imagePullPolicy` | Sidecar image pull policy | `IfNotPresent` | +| `sidecar.resources` | Sidecar resources | `{}` | +| `sidecar.securityContext` | Sidecar securityContext | `{}` | +| `sidecar.enableUniqueFilenames` | Sets the kiwigrid/k8s-sidecar UNIQUE_FILENAMES environment variable. If set to `true` the sidecar will create unique filenames where duplicate data keys exist between ConfigMaps and/or Secrets within the same or multiple Namespaces. | `false` | +| `sidecar.alerts.enabled` | Enables the cluster wide search for alerts and adds/updates/deletes them in grafana |`false` | +| `sidecar.alerts.label` | Label that config maps with alerts should have to be added | `grafana_alert` | +| `sidecar.alerts.labelValue` | Label value that config maps with alerts should have to be added | `""` | +| `sidecar.alerts.searchNamespace` | Namespaces list. If specified, the sidecar will search for alerts config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` | +| `sidecar.alerts.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` | +| `sidecar.alerts.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` | +| `sidecar.alerts.reloadURL` | Full url of datasource configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/alerting/reload"` | +| `sidecar.alerts.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` | +| `sidecar.alerts.initAlerts` | Set to true to deploy the alerts sidecar as an initContainer. This is needed if skipReload is true, to load any alerts defined at startup time. | `false` | +| `sidecar.alerts.extraMounts` | Additional alerts sidecar volume mounts. | `[]` | +| `sidecar.dashboards.enabled` | Enables the cluster wide search for dashboards and adds/updates/deletes them in grafana | `false` | +| `sidecar.dashboards.SCProvider` | Enables creation of sidecar provider | `true` | +| `sidecar.dashboards.provider.name` | Unique name of the grafana provider | `sidecarProvider` | +| `sidecar.dashboards.provider.orgid` | Id of the organisation, to which the dashboards should be added | `1` | +| `sidecar.dashboards.provider.folder` | Logical folder in which grafana groups dashboards | `""` | +| `sidecar.dashboards.provider.folderUid` | Allows you to specify the static UID for the logical folder above | `""` | +| `sidecar.dashboards.provider.disableDelete` | Activate to avoid the deletion of imported dashboards | `false` | +| `sidecar.dashboards.provider.allowUiUpdates` | Allow updating provisioned dashboards from the UI | `false` | +| `sidecar.dashboards.provider.type` | Provider type | `file` | +| `sidecar.dashboards.provider.foldersFromFilesStructure` | Allow Grafana to replicate dashboard structure from filesystem. | `false` | +| `sidecar.dashboards.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` | +| `sidecar.skipTlsVerify` | Set to true to skip tls verification for kube api calls | `nil` | +| `sidecar.dashboards.label` | Label that config maps with dashboards should have to be added | `grafana_dashboard` | +| `sidecar.dashboards.labelValue` | Label value that config maps with dashboards should have to be added | `""` | +| `sidecar.dashboards.folder` | Folder in the pod that should hold the collected dashboards (unless `sidecar.dashboards.defaultFolderName` is set). This path will be mounted. | `/tmp/dashboards` | +| `sidecar.dashboards.folderAnnotation` | The annotation the sidecar will look for in configmaps to override the destination folder for files | `nil` | +| `sidecar.dashboards.defaultFolderName` | The default folder name, it will create a subfolder under the `sidecar.dashboards.folder` and put dashboards in there instead | `nil` | +| `sidecar.dashboards.searchNamespace` | Namespaces list. If specified, the sidecar will search for dashboards config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` | +| `sidecar.dashboards.script` | Absolute path to shell script to execute after a configmap got reloaded. | `nil` | +| `sidecar.dashboards.reloadURL` | Full url of dashboards configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/dashboards/reload"` | +| `sidecar.dashboards.skipReload` | Enabling this omits defining the REQ_USERNAME, REQ_PASSWORD, REQ_URL and REQ_METHOD environment variables | `false` | +| `sidecar.dashboards.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` | +| `sidecar.dashboards.extraMounts` | Additional dashboard sidecar volume mounts. | `[]` | +| `sidecar.datasources.enabled` | Enables the cluster wide search for datasources and adds/updates/deletes them in grafana |`false` | +| `sidecar.datasources.label` | Label that config maps with datasources should have to be added | `grafana_datasource` | +| `sidecar.datasources.labelValue` | Label value that config maps with datasources should have to be added | `""` | +| `sidecar.datasources.searchNamespace` | Namespaces list. If specified, the sidecar will search for datasources config-maps inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` | +| `sidecar.datasources.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` | +| `sidecar.datasources.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` | +| `sidecar.datasources.reloadURL` | Full url of datasource configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/datasources/reload"` | +| `sidecar.datasources.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` | +| `sidecar.datasources.initDatasources` | Set to true to deploy the datasource sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any datasources defined at startup time. | `false` | +| `sidecar.notifiers.enabled` | Enables the cluster wide search for notifiers and adds/updates/deletes them in grafana | `false` | +| `sidecar.notifiers.label` | Label that config maps with notifiers should have to be added | `grafana_notifier` | +| `sidecar.notifiers.labelValue` | Label value that config maps with notifiers should have to be added | `""` | +| `sidecar.notifiers.searchNamespace` | Namespaces list. If specified, the sidecar will search for notifiers config-maps (or secrets) inside these namespaces. Otherwise the namespace in which the sidecar is running will be used. It's also possible to specify ALL to search in all namespaces. | `nil` | +| `sidecar.notifiers.watchMethod` | Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. | `WATCH` | +| `sidecar.notifiers.resource` | Should the sidecar looks into secrets, configmaps or both. | `both` | +| `sidecar.notifiers.reloadURL` | Full url of notifier configuration reload API endpoint, to invoke after a config-map change | `"http://localhost:3000/api/admin/provisioning/notifications/reload"` | +| `sidecar.notifiers.skipReload` | Enabling this omits defining the REQ_URL and REQ_METHOD environment variables | `false` | +| `sidecar.notifiers.initNotifiers` | Set to true to deploy the notifier sidecar as an initContainer in addition to a container. This is needed if skipReload is true, to load any notifiers defined at startup time. | `false` | +| `smtp.existingSecret` | The name of an existing secret containing the SMTP credentials. | `""` | +| `smtp.userKey` | The key in the existing SMTP secret containing the username. | `"user"` | +| `smtp.passwordKey` | The key in the existing SMTP secret containing the password. | `"password"` | +| `admin.existingSecret` | The name of an existing secret containing the admin credentials (can be templated). | `""` | +| `admin.userKey` | The key in the existing admin secret containing the username. | `"admin-user"` | +| `admin.passwordKey` | The key in the existing admin secret containing the password. | `"admin-password"` | +| `serviceAccount.automountServiceAccountToken` | Automount the service account token on all pods where is service account is used | `false` | +| `serviceAccount.annotations` | ServiceAccount annotations | | +| `serviceAccount.create` | Create service account | `true` | +| `serviceAccount.labels` | ServiceAccount labels | `{}` | +| `serviceAccount.name` | Service account name to use, when empty will be set to created account if `serviceAccount.create` is set else to `default` | `` | +| `serviceAccount.nameTest` | Service account name to use for test, when empty will be set to created account if `serviceAccount.create` is set else to `default` | `nil` | +| `rbac.create` | Create and use RBAC resources | `true` | +| `rbac.namespaced` | Creates Role and Rolebinding instead of the default ClusterRole and ClusteRoleBindings for the grafana instance | `false` | +| `rbac.useExistingRole` | Set to a rolename to use existing role - skipping role creating - but still doing serviceaccount and rolebinding to the rolename set here. | `nil` | +| `rbac.pspEnabled` | Create PodSecurityPolicy (with `rbac.create`, grant roles permissions as well) | `false` | +| `rbac.pspUseAppArmor` | Enforce AppArmor in created PodSecurityPolicy (requires `rbac.pspEnabled`) | `false` | +| `rbac.extraRoleRules` | Additional rules to add to the Role | [] | +| `rbac.extraClusterRoleRules` | Additional rules to add to the ClusterRole | [] | +| `command` | Define command to be executed by grafana container at startup | `nil` | +| `args` | Define additional args if command is used | `nil` | +| `testFramework.enabled` | Whether to create test-related resources | `true` | +| `testFramework.image.registry` | `test-framework` image registry. | `docker.io` | +| `testFramework.image.repository` | `test-framework` image repository. | `bats/bats` | +| `testFramework.image.tag` | `test-framework` image tag. | `v1.4.1` | +| `testFramework.imagePullPolicy` | `test-framework` image pull policy. | `IfNotPresent` | +| `testFramework.securityContext` | `test-framework` securityContext | `{}` | +| `downloadDashboards.env` | Environment variables to be passed to the `download-dashboards` container | `{}` | +| `downloadDashboards.envFromSecret` | Name of a Kubernetes secret (must be manually created in the same namespace) containing values to be added to the environment. Can be templated | `""` | +| `downloadDashboards.resources` | Resources of `download-dashboards` container | `{}` | +| `downloadDashboardsImage.registry` | Curl docker image registry | `docker.io` | +| `downloadDashboardsImage.repository` | Curl docker image repository | `curlimages/curl` | +| `downloadDashboardsImage.tag` | Curl docker image tag | `7.73.0` | +| `downloadDashboardsImage.sha` | Curl docker image sha (optional) | `""` | +| `downloadDashboardsImage.pullPolicy` | Curl docker image pull policy | `IfNotPresent` | +| `namespaceOverride` | Override the deployment namespace | `""` (`Release.Namespace`) | +| `serviceMonitor.enabled` | Use servicemonitor from prometheus operator | `false` | +| `serviceMonitor.namespace` | Namespace this servicemonitor is installed in | | +| `serviceMonitor.interval` | How frequently Prometheus should scrape | `1m` | +| `serviceMonitor.path` | Path to scrape | `/metrics` | +| `serviceMonitor.scheme` | Scheme to use for metrics scraping | `http` | +| `serviceMonitor.tlsConfig` | TLS configuration block for the endpoint | `{}` | +| `serviceMonitor.labels` | Labels for the servicemonitor passed to Prometheus Operator | `{}` | +| `serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended | `30s` | +| `serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping. | `[]` | +| `serviceMonitor.metricRelabelings` | MetricRelabelConfigs to apply to samples before ingestion. | `[]` | +| `revisionHistoryLimit` | Number of old ReplicaSets to retain | `10` | +| `imageRenderer.enabled` | Enable the image-renderer deployment & service | `false` | +| `imageRenderer.image.registry` | image-renderer Image registry | `docker.io` | +| `imageRenderer.image.repository` | image-renderer Image repository | `grafana/grafana-image-renderer` | +| `imageRenderer.image.tag` | image-renderer Image tag | `latest` | +| `imageRenderer.image.sha` | image-renderer Image sha (optional) | `""` | +| `imageRenderer.image.pullPolicy` | image-renderer ImagePullPolicy | `Always` | +| `imageRenderer.env` | extra env-vars for image-renderer | `{}` | +| `imageRenderer.envValueFrom` | Environment variables for image-renderer from alternate sources. See the API docs on [EnvVarSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#envvarsource-v1-core) for format details. Can be templated | `{}` | +| `imageRenderer.extraConfigmapMounts` | Additional image-renderer configMap volume mounts (values are templated) | `[]` | +| `imageRenderer.extraSecretMounts` | Additional image-renderer secret volume mounts | `[]` | +| `imageRenderer.extraVolumeMounts` | Additional image-renderer volume mounts | `[]` | +| `imageRenderer.extraVolumes` | Additional image-renderer volumes | `[]` | +| `imageRenderer.serviceAccountName` | image-renderer deployment serviceAccountName | `""` | +| `imageRenderer.securityContext` | image-renderer deployment securityContext | `{}` | +| `imageRenderer.podAnnotations` | image-renderer image-renderer pod annotation | `{}` | +| `imageRenderer.hostAliases` | image-renderer deployment Host Aliases | `[]` | +| `imageRenderer.priorityClassName` | image-renderer deployment priority class | `''` | +| `imageRenderer.service.enabled` | Enable the image-renderer service | `true` | +| `imageRenderer.service.portName` | image-renderer service port name | `http` | +| `imageRenderer.service.port` | image-renderer port used by deployment | `8081` | +| `imageRenderer.service.targetPort` | image-renderer service port used by service | `8081` | +| `imageRenderer.appProtocol` | Adds the appProtocol field to the service | `` | +| `imageRenderer.grafanaSubPath` | Grafana sub path to use for image renderer callback url | `''` | +| `imageRenderer.podPortName` | name of the image-renderer port on the pod | `http` | +| `imageRenderer.revisionHistoryLimit` | number of image-renderer replica sets to keep | `10` | +| `imageRenderer.networkPolicy.limitIngress` | Enable a NetworkPolicy to limit inbound traffic from only the created grafana pods | `true` | +| `imageRenderer.networkPolicy.limitEgress` | Enable a NetworkPolicy to limit outbound traffic to only the created grafana pods | `false` | +| `imageRenderer.resources` | Set resource limits for image-renderer pods | `{}` | +| `imageRenderer.nodeSelector` | Node labels for pod assignment | `{}` | +| `imageRenderer.tolerations` | Toleration labels for pod assignment | `[]` | +| `imageRenderer.affinity` | Affinity settings for pod assignment | `{}` | +| `networkPolicy.enabled` | Enable creation of NetworkPolicy resources. | `false` | +| `networkPolicy.allowExternal` | Don't require client label for connections | `true` | +| `networkPolicy.explicitNamespacesSelector` | A Kubernetes LabelSelector to explicitly select namespaces from which traffic could be allowed | `{}` | +| `networkPolicy.ingress` | Enable the creation of an ingress network policy | `true` | +| `networkPolicy.egress.enabled` | Enable the creation of an egress network policy | `false` | +| `networkPolicy.egress.ports` | An array of ports to allow for the egress | `[]` | +| `enableKubeBackwardCompatibility` | Enable backward compatibility of kubernetes where pod's defintion version below 1.13 doesn't have the enableServiceLinks option | `false` | + +### Example ingress with path + +With grafana 6.3 and above + +```yaml +grafana.ini: + server: + domain: monitoring.example.com + root_url: "%(protocol)s://%(domain)s/grafana" + serve_from_sub_path: true +ingress: + enabled: true + hosts: + - "monitoring.example.com" + path: "/grafana" +``` + +### Example of extraVolumeMounts and extraVolumes + +Configure additional volumes with `extraVolumes` and volume mounts with `extraVolumeMounts`. + +Example for `extraVolumeMounts` and corresponding `extraVolumes`: + +```yaml +extraVolumeMounts: + - name: plugins + mountPath: /var/lib/grafana/plugins + subPath: configs/grafana/plugins + readOnly: false + - name: dashboards + mountPath: /var/lib/grafana/dashboards + hostPath: /usr/shared/grafana/dashboards + readOnly: false + +extraVolumes: + - name: plugins + existingClaim: existing-grafana-claim + - name: dashboards + hostPath: /usr/shared/grafana/dashboards +``` + +Volumes default to `emptyDir`. Set to `persistentVolumeClaim`, +`hostPath`, `csi`, or `configMap` for other types. For a +`persistentVolumeClaim`, specify an existing claim name with +`existingClaim`. + +## Import dashboards + +There are a few methods to import dashboards to Grafana. Below are some examples and explanations as to how to use each method: + +```yaml +dashboards: + default: + some-dashboard: + json: | + { + "annotations": + + ... + # Complete json file here + ... + + "title": "Some Dashboard", + "uid": "abcd1234", + "version": 1 + } + custom-dashboard: + # This is a path to a file inside the dashboards directory inside the chart directory + file: dashboards/custom-dashboard.json + prometheus-stats: + # Ref: https://grafana.com/dashboards/2 + gnetId: 2 + revision: 2 + datasource: Prometheus + loki-dashboard-quick-search: + gnetId: 12019 + revision: 2 + datasource: + - name: DS_PROMETHEUS + value: Prometheus + - name: DS_LOKI + value: Loki + local-dashboard: + url: https://raw.githubusercontent.com/user/repository/master/dashboards/dashboard.json +``` + +## BASE64 dashboards + +Dashboards could be stored on a server that does not return JSON directly and instead of it returns a Base64 encoded file (e.g. Gerrit) +A new parameter has been added to the url use case so if you specify a b64content value equals to true after the url entry a Base64 decoding is applied before save the file to disk. +If this entry is not set or is equals to false not decoding is applied to the file before saving it to disk. + +### Gerrit use case + +Gerrit API for download files has the following schema: where {project-name} and +{file-id} usually has '/' in their values and so they MUST be replaced by %2F so if project-name is user/repo, branch-id is master and file-id is equals to dir1/dir2/dashboard +the url value is + +## Sidecar for dashboards + +If the parameter `sidecar.dashboards.enabled` is set, a sidecar container is deployed in the grafana +pod. This container watches all configmaps (or secrets) in the cluster and filters out the ones with +a label as defined in `sidecar.dashboards.label`. The files defined in those configmaps are written +to a folder and accessed by grafana. Changes to the configmaps are monitored and the imported +dashboards are deleted/updated. + +A recommendation is to use one configmap per dashboard, as a reduction of multiple dashboards inside +one configmap is currently not properly mirrored in grafana. + +Example dashboard config: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: sample-grafana-dashboard + labels: + grafana_dashboard: "1" +data: + k8s-dashboard.json: |- + [...] +``` + +## Sidecar for datasources + +If the parameter `sidecar.datasources.enabled` is set, an init container is deployed in the grafana +pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and +filters out the ones with a label as defined in `sidecar.datasources.label`. The files defined in +those secrets are written to a folder and accessed by grafana on startup. Using these yaml files, +the data sources in grafana can be imported. + +Should you aim for reloading datasources in Grafana each time the config is changed, set `sidecar.datasources.skipReload: false` and adjust `sidecar.datasources.reloadURL` to `http://..svc.cluster.local/api/admin/provisioning/datasources/reload`. + +Secrets are recommended over configmaps for this usecase because datasources usually contain private +data like usernames and passwords. Secrets are the more appropriate cluster resource to manage those. + +Example values to add a postgres datasource as a kubernetes secret: +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: grafana-datasources + labels: + grafana_datasource: 'true' # default value for: sidecar.datasources.label +stringData: + pg-db.yaml: |- + apiVersion: 1 + datasources: + - name: My pg db datasource + type: postgres + url: my-postgresql-db:5432 + user: db-readonly-user + secureJsonData: + password: 'SUperSEcretPa$$word' + jsonData: + database: my_datase + sslmode: 'disable' # disable/require/verify-ca/verify-full + maxOpenConns: 0 # Grafana v5.4+ + maxIdleConns: 2 # Grafana v5.4+ + connMaxLifetime: 14400 # Grafana v5.4+ + postgresVersion: 1000 # 903=9.3, 904=9.4, 905=9.5, 906=9.6, 1000=10 + timescaledb: false + # allow users to edit datasources from the UI. + editable: false +``` + +Example values to add a datasource adapted from [Grafana](http://docs.grafana.org/administration/provisioning/#example-datasource-config-file): + +```yaml +datasources: + datasources.yaml: + apiVersion: 1 + datasources: + # name of the datasource. Required + - name: Graphite + # datasource type. Required + type: graphite + # access mode. proxy or direct (Server or Browser in the UI). Required + access: proxy + # org id. will default to orgId 1 if not specified + orgId: 1 + # url + url: http://localhost:8080 + # database password, if used + password: + # database user, if used + user: + # database name, if used + database: + # enable/disable basic auth + basicAuth: + # basic auth username + basicAuthUser: + # basic auth password + basicAuthPassword: + # enable/disable with credentials headers + withCredentials: + # mark as default datasource. Max one per org + isDefault: + # fields that will be converted to json and stored in json_data + jsonData: + graphiteVersion: "1.1" + tlsAuth: true + tlsAuthWithCACert: true + # json object of data that will be encrypted. + secureJsonData: + tlsCACert: "..." + tlsClientCert: "..." + tlsClientKey: "..." + version: 1 + # allow users to edit datasources from the UI. + editable: false +``` + +## Sidecar for notifiers + +If the parameter `sidecar.notifiers.enabled` is set, an init container is deployed in the grafana +pod. This container lists all secrets (or configmaps, though not recommended) in the cluster and +filters out the ones with a label as defined in `sidecar.notifiers.label`. The files defined in +those secrets are written to a folder and accessed by grafana on startup. Using these yaml files, +the notification channels in grafana can be imported. The secrets must be created before +`helm install` so that the notifiers init container can list the secrets. + +Secrets are recommended over configmaps for this usecase because alert notification channels usually contain +private data like SMTP usernames and passwords. Secrets are the more appropriate cluster resource to manage those. + +Example datasource config adapted from [Grafana](https://grafana.com/docs/grafana/latest/administration/provisioning/#alert-notification-channels): + +```yaml +notifiers: + - name: notification-channel-1 + type: slack + uid: notifier1 + # either + org_id: 2 + # or + org_name: Main Org. + is_default: true + send_reminder: true + frequency: 1h + disable_resolve_message: false + # See `Supported Settings` section for settings supporter for each + # alert notification type. + settings: + recipient: 'XXX' + token: 'xoxb' + uploadImage: true + url: https://slack.com + +delete_notifiers: + - name: notification-channel-1 + uid: notifier1 + org_id: 2 + - name: notification-channel-2 + # default org_id: 1 +``` + +## Sidecar for alerting resources + +If the parameter `sidecar.alerts.enabled` is set, a sidecar container is deployed in the grafana +pod. This container watches all configmaps (or secrets) in the cluster (namespace defined by `sidecar.alerts.searchNamespace`) and filters out the ones with +a label as defined in `sidecar.alerts.label` (default is `grafana_alert`). The files defined in those configmaps are written +to a folder and accessed by grafana. Changes to the configmaps are monitored and the imported alerting resources are updated, however, deletions are a little more complicated (see below). + +This sidecar can be used to provision alert rules, contact points, notification policies, notification templates and mute timings as shown in [Grafana Documentation](https://grafana.com/docs/grafana/next/alerting/set-up/provision-alerting-resources/file-provisioning/). + +To fetch the alert config which will be provisioned, use the alert provisioning API ([Grafana Documentation](https://grafana.com/docs/grafana/next/developers/http_api/alerting_provisioning/)). +You can use either JSON or YAML format. + +Example config for an alert rule: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: sample-grafana-alert + labels: + grafana_alert: "1" +data: + k8s-alert.yml: |- + apiVersion: 1 + groups: + - orgId: 1 + name: k8s-alert + [...] +``` + +To delete provisioned alert rules is a two step process, you need to delete the configmap which defined the alert rule +and then create a configuration which deletes the alert rule. + +Example deletion configuration: +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: delete-sample-grafana-alert + namespace: monitoring + labels: + grafana_alert: "1" +data: + delete-k8s-alert.yml: |- + apiVersion: 1 + deleteRules: + - orgId: 1 + uid: 16624780-6564-45dc-825c-8bded4ad92d3 +``` + +## Statically provision alerting resources +If you don't need to change alerting resources (alert rules, contact points, notification policies and notification templates) regularly you could use the `alerting` config option instead of the sidecar option above. +This will grab the alerting config and apply it statically at build time for the helm file. + +There are two methods to statically provision alerting configuration in Grafana. Below are some examples and explanations as to how to use each method: + +```yaml +alerting: + team1-alert-rules.yaml: + file: alerting/team1/rules.yaml + team2-alert-rules.yaml: + file: alerting/team2/rules.yaml + team3-alert-rules.yaml: + file: alerting/team3/rules.yaml + notification-policies.yaml: + file: alerting/shared/notification-policies.yaml + notification-templates.yaml: + file: alerting/shared/notification-templates.yaml + contactpoints.yaml: + apiVersion: 1 + contactPoints: + - orgId: 1 + name: Slack channel + receivers: + - uid: default-receiver + type: slack + settings: + # Webhook URL to be filled in + url: "" + # We need to escape double curly braces for the tpl function. + text: '{{ `{{ template "default.message" . }}` }}' + title: '{{ `{{ template "default.title" . }}` }}' +``` + +The two possibilities for static alerting resource provisioning are: + +* Inlining the file contents as shown for contact points in the above example. +* Importing a file using a relative path starting from the chart root directory as shown for the alert rules in the above example. + +### Important notes on file provisioning + +* The format of the files is defined in the [Grafana documentation](https://grafana.com/docs/grafana/next/alerting/set-up/provision-alerting-resources/file-provisioning/) on file provisioning. +* The chart supports importing YAML and JSON files. +* The filename must be unique, otherwise one volume mount will overwrite the other. +* In case of inlining, double curly braces that arise from the Grafana configuration format and are not intended as templates for the chart must be escaped. +* The number of total files under `alerting:` is not limited. Each file will end up as a volume mount in the corresponding provisioning folder of the deployed Grafana instance. +* The file size for each import is limited by what the function `.Files.Get` can handle, which suffices for most cases. + +## How to serve Grafana with a path prefix (/grafana) + +In order to serve Grafana with a prefix (e.g., ), add the following to your values.yaml. + +```yaml +ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "nginx" + nginx.ingress.kubernetes.io/rewrite-target: /$1 + nginx.ingress.kubernetes.io/use-regex: "true" + + path: /grafana/?(.*) + hosts: + - k8s.example.dev + +grafana.ini: + server: + root_url: http://localhost:3000/grafana # this host can be localhost +``` + +## How to securely reference secrets in grafana.ini + +This example uses Grafana [file providers](https://grafana.com/docs/grafana/latest/administration/configuration/#file-provider) for secret values and the `extraSecretMounts` configuration flag (Additional grafana server secret mounts) to mount the secrets. + +In grafana.ini: + +```yaml +grafana.ini: + [auth.generic_oauth] + enabled = true + client_id = $__file{/etc/secrets/auth_generic_oauth/client_id} + client_secret = $__file{/etc/secrets/auth_generic_oauth/client_secret} +``` + +Existing secret, or created along with helm: + +```yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: auth-generic-oauth-secret +type: Opaque +stringData: + client_id: + client_secret: +``` + +Include in the `extraSecretMounts` configuration flag: + +```yaml +- extraSecretMounts: + - name: auth-generic-oauth-secret-mount + secretName: auth-generic-oauth-secret + defaultMode: 0440 + mountPath: /etc/secrets/auth_generic_oauth + readOnly: true +``` + +### extraSecretMounts using a Container Storage Interface (CSI) provider + +This example uses a CSI driver e.g. retrieving secrets using [Azure Key Vault Provider](https://github.com/Azure/secrets-store-csi-driver-provider-azure) + +```yaml +- extraSecretMounts: + - name: secrets-store-inline + mountPath: /run/secrets + readOnly: true + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: "my-provider" + nodePublishSecretRef: + name: akv-creds +``` + +## Image Renderer Plug-In + +This chart supports enabling [remote image rendering](https://github.com/grafana/grafana-image-renderer/blob/master/README.md#run-in-docker) + +```yaml +imageRenderer: + enabled: true +``` + +### Image Renderer NetworkPolicy + +By default the image-renderer pods will have a network policy which only allows ingress traffic from the created grafana instance + +### High Availability for unified alerting + +If you want to run Grafana in a high availability cluster you need to enable +the headless service by setting `headlessService: true` in your `values.yaml` +file. + +As next step you have to setup the `grafana.ini` in your `values.yaml` in a way +that it will make use of the headless service to obtain all the IPs of the +cluster. You should replace ``{{ Name }}`` with the name of your helm deployment. + +```yaml +grafana.ini: + ... + unified_alerting: + enabled: true + ha_peers: {{ Name }}-headless:9094 + ha_listen_address: ${POD_IP}:9094 + ha_advertise_address: ${POD_IP}:9094 + + alerting: + enabled: false +``` diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/dashboards/custom-dashboard.json b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/dashboards/custom-dashboard.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/dashboards/custom-dashboard.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/NOTES.txt b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/NOTES.txt new file mode 100644 index 0000000000..a40f666a47 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/NOTES.txt @@ -0,0 +1,55 @@ +1. Get your '{{ .Values.adminUser }}' user password by running: + + kubectl get secret --namespace {{ include "grafana.namespace" . }} {{ .Values.admin.existingSecret | default (include "grafana.fullname" .) }} -o jsonpath="{.data.{{ .Values.admin.passwordKey | default "admin-password" }}}" | base64 --decode ; echo + + +2. The Grafana server can be accessed via port {{ .Values.service.port }} on the following DNS name from within your cluster: + + {{ include "grafana.fullname" . }}.{{ include "grafana.namespace" . }}.svc.cluster.local +{{ if .Values.ingress.enabled }} + If you bind grafana to 80, please update values in values.yaml and reinstall: + ``` + securityContext: + runAsUser: 0 + runAsGroup: 0 + fsGroup: 0 + + command: + - "setcap" + - "'cap_net_bind_service=+ep'" + - "/usr/sbin/grafana-server &&" + - "sh" + - "/run.sh" + ``` + Details refer to https://grafana.com/docs/installation/configuration/#http-port. + Or grafana would always crash. + + From outside the cluster, the server URL(s) are: + {{- range .Values.ingress.hosts }} + http://{{ . }} + {{- end }} +{{- else }} + Get the Grafana URL to visit by running these commands in the same shell: + {{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ include "grafana.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "grafana.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ include "grafana.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT + {{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc --namespace {{ include "grafana.namespace" . }} -w {{ include "grafana.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ include "grafana.namespace" . }} {{ include "grafana.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + http://$SERVICE_IP:{{ .Values.service.port -}} + {{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ include "grafana.namespace" . }} -l "app.kubernetes.io/name={{ include "grafana.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + kubectl --namespace {{ include "grafana.namespace" . }} port-forward $POD_NAME 3000 + {{- end }} +{{- end }} + +3. Login with the password from step 1 and the username: {{ .Values.adminUser }} + +{{- if and (not .Values.persistence.enabled) (not .Values.persistence.disableWarning) }} +################################################################################# +###### WARNING: Persistence is disabled!!! You will lose your data when ##### +###### the Grafana pod is terminated. ##### +################################################################################# +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_config.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_config.tpl new file mode 100644 index 0000000000..b866217f2e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_config.tpl @@ -0,0 +1,172 @@ +{{/* + Generate config map data + */}} +{{- define "grafana.configData" -}} +{{ include "grafana.assertNoLeakedSecrets" . }} +{{- $files := .Files }} +{{- $root := . -}} +{{- with .Values.plugins }} +plugins: {{ join "," . }} +{{- end }} +grafana.ini: | +{{- range $elem, $elemVal := index .Values "grafana.ini" }} + {{- if not (kindIs "map" $elemVal) }} + {{- if kindIs "invalid" $elemVal }} + {{ $elem }} = + {{- else if kindIs "string" $elemVal }} + {{ $elem }} = {{ tpl $elemVal $ }} + {{- else }} + {{ $elem }} = {{ $elemVal }} + {{- end }} + {{- end }} +{{- end }} +{{- range $key, $value := index .Values "grafana.ini" }} + {{- if kindIs "map" $value }} + [{{ $key }}] + {{- range $elem, $elemVal := $value }} + {{- if kindIs "invalid" $elemVal }} + {{ $elem }} = + {{- else if kindIs "string" $elemVal }} + {{ $elem }} = {{ tpl $elemVal $ }} + {{- else }} + {{ $elem }} = {{ $elemVal }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} + +{{- range $key, $value := .Values.datasources }} +{{- if not (hasKey $value "secret") }} +{{ $key }}: | + {{- tpl (toYaml $value | nindent 2) $root }} +{{- end }} +{{- end }} + +{{- range $key, $value := .Values.notifiers }} +{{- if not (hasKey $value "secret") }} +{{ $key }}: | + {{- toYaml $value | nindent 2 }} +{{- end }} +{{- end }} + +{{- range $key, $value := .Values.alerting }} +{{- if (hasKey $value "file") }} +{{ $key }}: +{{- toYaml ( $files.Get $value.file ) | nindent 2 }} +{{- else if (or (hasKey $value "secret") (hasKey $value "secretFile"))}} +{{/* will be stored inside secret generated by "configSecret.yaml"*/}} +{{- else }} +{{ $key }}: | + {{- tpl (toYaml $value | nindent 2) $root }} +{{- end }} +{{- end }} + +{{- range $key, $value := .Values.dashboardProviders }} +{{ $key }}: | + {{- toYaml $value | nindent 2 }} +{{- end }} + +{{- if .Values.dashboards }} +download_dashboards.sh: | + #!/usr/bin/env sh + set -euf + {{- if .Values.dashboardProviders }} + {{- range $key, $value := .Values.dashboardProviders }} + {{- range $value.providers }} + mkdir -p {{ .options.path }} + {{- end }} + {{- end }} + {{- end }} +{{ $dashboardProviders := .Values.dashboardProviders }} +{{- range $provider, $dashboards := .Values.dashboards }} + {{- range $key, $value := $dashboards }} + {{- if (or (hasKey $value "gnetId") (hasKey $value "url")) }} + curl -skf \ + --connect-timeout 60 \ + --max-time 60 \ + {{- if not $value.b64content }} + {{- if not $value.acceptHeader }} + -H "Accept: application/json" \ + {{- else }} + -H "Accept: {{ $value.acceptHeader }}" \ + {{- end }} + {{- if $value.token }} + -H "Authorization: token {{ $value.token }}" \ + {{- end }} + {{- if $value.bearerToken }} + -H "Authorization: Bearer {{ $value.bearerToken }}" \ + {{- end }} + {{- if $value.basic }} + -H "Authorization: Basic {{ $value.basic }}" \ + {{- end }} + {{- if $value.gitlabToken }} + -H "PRIVATE-TOKEN: {{ $value.gitlabToken }}" \ + {{- end }} + -H "Content-Type: application/json;charset=UTF-8" \ + {{- end }} + {{- $dpPath := "" -}} + {{- range $kd := (index $dashboardProviders "dashboardproviders.yaml").providers }} + {{- if eq $kd.name $provider }} + {{- $dpPath = $kd.options.path }} + {{- end }} + {{- end }} + {{- if $value.url }} + "{{ $value.url }}" \ + {{- else }} + "https://grafana.com/api/dashboards/{{ $value.gnetId }}/revisions/{{- if $value.revision -}}{{ $value.revision }}{{- else -}}1{{- end -}}/download" \ + {{- end }} + {{- if $value.datasource }} + {{- if kindIs "string" $value.datasource }} + | sed '/-- .* --/! s/"datasource":.*,/"datasource": "{{ $value.datasource }}",/g' \ + {{- end }} + {{- if kindIs "slice" $value.datasource }} + {{- range $value.datasource }} + | sed '/-- .* --/! s/${{"{"}}{{ .name }}}/{{ .value }}/g' \ + {{- end }} + {{- end }} + {{- end }} + {{- if $value.b64content }} + | base64 -d \ + {{- end }} + > "{{- if $dpPath -}}{{ $dpPath }}{{- else -}}/var/lib/grafana/dashboards/{{ $provider }}{{- end -}}/{{ $key }}.json" + {{ end }} + {{- end }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* + Generate dashboard json config map data + */}} +{{- define "grafana.configDashboardProviderData" -}} +provider.yaml: |- + apiVersion: 1 + providers: + - name: '{{ .Values.sidecar.dashboards.provider.name }}' + orgId: {{ .Values.sidecar.dashboards.provider.orgid }} + {{- if not .Values.sidecar.dashboards.provider.foldersFromFilesStructure }} + folder: '{{ .Values.sidecar.dashboards.provider.folder }}' + folderUid: '{{ .Values.sidecar.dashboards.provider.folderUid }}' + {{- end }} + type: {{ .Values.sidecar.dashboards.provider.type }} + disableDeletion: {{ .Values.sidecar.dashboards.provider.disableDelete }} + allowUiUpdates: {{ .Values.sidecar.dashboards.provider.allowUiUpdates }} + updateIntervalSeconds: {{ .Values.sidecar.dashboards.provider.updateIntervalSeconds | default 30 }} + options: + foldersFromFilesStructure: {{ .Values.sidecar.dashboards.provider.foldersFromFilesStructure }} + path: {{ .Values.sidecar.dashboards.folder }}{{- with .Values.sidecar.dashboards.defaultFolderName }}/{{ . }}{{- end }} +{{- end -}} + +{{- define "grafana.secretsData" -}} +{{- if and (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) }} +admin-user: {{ .Values.adminUser | b64enc | quote }} +{{- if .Values.adminPassword }} +admin-password: {{ .Values.adminPassword | b64enc | quote }} +{{- else }} +admin-password: {{ include "grafana.password" . }} +{{- end }} +{{- end }} +{{- if not .Values.ldap.existingSecret }} +ldap-toml: {{ tpl .Values.ldap.config $ | b64enc | quote }} +{{- end }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_helpers.tpl new file mode 100644 index 0000000000..68d2d815d8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_helpers.tpl @@ -0,0 +1,305 @@ +# Rancher +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "grafana.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 "grafana.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 "grafana.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create the name of the service account +*/}} +{{- define "grafana.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "grafana.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "grafana.serviceAccountNameTest" -}} +{{- if .Values.serviceAccount.create }} +{{- default (print (include "grafana.fullname" .) "-test") .Values.serviceAccount.nameTest }} +{{- else }} +{{- default "default" .Values.serviceAccount.nameTest }} +{{- end }} +{{- end }} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "grafana.namespace" -}} +{{- if .Values.namespaceOverride }} +{{- .Values.namespaceOverride }} +{{- else }} +{{- .Release.Namespace }} +{{- end }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "grafana.labels" -}} +helm.sh/chart: {{ include "grafana.chart" . }} +{{ include "grafana.selectorLabels" . }} +{{- if or .Chart.AppVersion .Values.image.tag }} +app.kubernetes.io/version: {{ mustRegexReplaceAllLiteral "@sha.*" .Values.image.tag "" | default .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- with .Values.extraLabels }} +{{ toYaml . }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "grafana.selectorLabels" -}} +app.kubernetes.io/name: {{ include "grafana.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "grafana.imageRenderer.labels" -}} +helm.sh/chart: {{ include "grafana.chart" . }} +{{ include "grafana.imageRenderer.selectorLabels" . }} +{{- if or .Chart.AppVersion .Values.image.tag }} +app.kubernetes.io/version: {{ mustRegexReplaceAllLiteral "@sha.*" .Values.image.tag "" | default .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels ImageRenderer +*/}} +{{- define "grafana.imageRenderer.selectorLabels" -}} +app.kubernetes.io/name: {{ include "grafana.name" . }}-image-renderer +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Looks if there's an existing secret and reuse its password. If not it generates +new password and use it. +*/}} +{{- define "grafana.password" -}} +{{- $secret := (lookup "v1" "Secret" (include "grafana.namespace" .) (include "grafana.fullname" .) ) }} +{{- if $secret }} +{{- index $secret "data" "admin-password" }} +{{- else }} +{{- (randAlphaNum 40) | b64enc | quote }} +{{- end }} +{{- end }} + +{{/* +Return the appropriate apiVersion for rbac. +*/}} +{{- define "grafana.rbac.apiVersion" -}} +{{- if $.Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1" }} +{{- print "rbac.authorization.k8s.io/v1" }} +{{- else }} +{{- print "rbac.authorization.k8s.io/v1beta1" }} +{{- end }} +{{- end }} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "grafana.ingress.apiVersion" -}} +{{- if and ($.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" .Capabilities.KubeVersion.Version) }} +{{- print "networking.k8s.io/v1" }} +{{- else if $.Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" }} +{{- print "networking.k8s.io/v1beta1" }} +{{- else }} +{{- print "extensions/v1beta1" }} +{{- end }} +{{- end }} + +{{/* +Return the appropriate apiVersion for Horizontal Pod Autoscaler. +*/}} +{{- define "grafana.hpa.apiVersion" -}} +{{- if .Capabilities.APIVersions.Has "autoscaling/v2" }} +{{- print "autoscaling/v2" }} +{{- else }} +{{- print "autoscaling/v2beta2" }} +{{- end }} +{{- end }} + +{{/* +Return the appropriate apiVersion for podDisruptionBudget. +*/}} +{{- define "grafana.podDisruptionBudget.apiVersion" -}} +{{- if $.Values.podDisruptionBudget.apiVersion }} +{{- print $.Values.podDisruptionBudget.apiVersion }} +{{- else if $.Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }} +{{- print "policy/v1" }} +{{- else }} +{{- print "policy/v1beta1" }} +{{- end }} +{{- end }} + +{{/* +Return if ingress is stable. +*/}} +{{- define "grafana.ingress.isStable" -}} +{{- eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1" }} +{{- end }} + +{{/* +Return if ingress supports ingressClassName. +*/}} +{{- define "grafana.ingress.supportsIngressClassName" -}} +{{- or (eq (include "grafana.ingress.isStable" .) "true") (and (eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) }} +{{- end }} + +{{/* +Return if ingress supports pathType. +*/}} +{{- define "grafana.ingress.supportsPathType" -}} +{{- or (eq (include "grafana.ingress.isStable" .) "true") (and (eq (include "grafana.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" .Capabilities.KubeVersion.Version)) }} +{{- end }} + +{{/* +Formats imagePullSecrets. Input is (dict "root" . "imagePullSecrets" .{specific imagePullSecrets}) +*/}} +{{- define "grafana.imagePullSecrets" -}} +{{- $root := .root }} +{{- range (concat .root.Values.global.imagePullSecrets .imagePullSecrets) }} +{{- if eq (typeOf .) "map[string]interface {}" }} +- {{ toYaml (dict "name" (tpl .name $root)) | trim }} +{{- else }} +- name: {{ tpl . $root }} +{{- end }} +{{- end }} +{{- end }} + + +{{/* + Checks whether or not the configSecret secret has to be created + */}} +{{- define "grafana.shouldCreateConfigSecret" -}} +{{- $secretFound := false -}} +{{- range $key, $value := .Values.datasources }} + {{- if hasKey $value "secret" }} + {{- $secretFound = true}} + {{- end }} +{{- end }} +{{- range $key, $value := .Values.notifiers }} + {{- if hasKey $value "secret" }} + {{- $secretFound = true}} + {{- end }} +{{- end }} +{{- range $key, $value := .Values.alerting }} + {{- if (or (hasKey $value "secret") (hasKey $value "secretFile")) }} + {{- $secretFound = true}} + {{- end }} +{{- end }} +{{- $secretFound}} +{{- end -}} + +{{/* + Checks whether the user is attempting to store secrets in plaintext + in the grafana.ini configmap +*/}} +{{/* grafana.assertNoLeakedSecrets checks for sensitive keys in values */}} +{{- define "grafana.assertNoLeakedSecrets" -}} + {{- $sensitiveKeysYaml := ` +sensitiveKeys: +- path: ["database", "password"] +- path: ["smtp", "password"] +- path: ["security", "secret_key"] +- path: ["security", "admin_password"] +- path: ["auth.basic", "password"] +- path: ["auth.ldap", "bind_password"] +- path: ["auth.google", "client_secret"] +- path: ["auth.github", "client_secret"] +- path: ["auth.gitlab", "client_secret"] +- path: ["auth.generic_oauth", "client_secret"] +- path: ["auth.okta", "client_secret"] +- path: ["auth.azuread", "client_secret"] +- path: ["auth.grafana_com", "client_secret"] +- path: ["auth.grafananet", "client_secret"] +- path: ["azure", "user_identity_client_secret"] +- path: ["unified_alerting", "ha_redis_password"] +- path: ["metrics", "basic_auth_password"] +- path: ["external_image_storage.s3", "secret_key"] +- path: ["external_image_storage.webdav", "password"] +- path: ["external_image_storage.azure_blob", "account_key"] +` | fromYaml -}} + {{- if $.Values.assertNoLeakedSecrets -}} + {{- $grafanaIni := index .Values "grafana.ini" -}} + {{- range $_, $secret := $sensitiveKeysYaml.sensitiveKeys -}} + {{- $currentMap := $grafanaIni -}} + {{- $shouldContinue := true -}} + {{- range $index, $elem := $secret.path -}} + {{- if and $shouldContinue (hasKey $currentMap $elem) -}} + {{- if eq (len $secret.path) (add1 $index) -}} + {{- if not (regexMatch "\\$(?:__(?:env|file|vault))?{[^}]+}" (index $currentMap $elem)) -}} + {{- fail (printf "Sensitive key '%s' should not be defined explicitly in values. Use variable expansion instead. You can disable this client-side validation by changing the value of assertNoLeakedSecrets." (join "." $secret.path)) -}} + {{- end -}} + {{- else -}} + {{- $currentMap = index $currentMap $elem -}} + {{- end -}} + {{- else -}} + {{- $shouldContinue = false -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_pod.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_pod.tpl new file mode 100644 index 0000000000..44526e5239 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/_pod.tpl @@ -0,0 +1,1306 @@ +{{- define "grafana.pod" -}} +{{- $sts := list "sts" "StatefulSet" "statefulset" -}} +{{- $root := . -}} +{{- with .Values.schedulerName }} +schedulerName: "{{ . }}" +{{- end }} +serviceAccountName: {{ include "grafana.serviceAccountName" . }} +automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} +{{- with .Values.securityContext }} +securityContext: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- with .Values.hostAliases }} +hostAliases: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- if .Values.dnsPolicy }} +dnsPolicy: {{ .Values.dnsPolicy }} +{{- end }} +{{- with .Values.dnsConfig }} +dnsConfig: + {{- toYaml . | nindent 2 }} +{{- end }} +{{- with .Values.priorityClassName }} +priorityClassName: {{ . }} +{{- end }} +{{- if ( or .Values.persistence.enabled .Values.dashboards .Values.extraInitContainers (and .Values.sidecar.alerts.enabled .Values.sidecar.alerts.initAlerts) (and .Values.sidecar.datasources.enabled .Values.sidecar.datasources.initDatasources) (and .Values.sidecar.notifiers.enabled .Values.sidecar.notifiers.initNotifiers)) }} +initContainers: +{{- end }} +{{- if ( and .Values.persistence.enabled .Values.initChownData.enabled ) }} + - name: init-chown-data + {{- $registry := include "system_default_registry" . | default .Values.initChownData.image.registry -}} + {{- if .Values.initChownData.image.sha }} + image: "{{ $registry }}{{ .Values.initChownData.image.repository }}:{{ .Values.initChownData.image.tag }}@sha256:{{ .Values.initChownData.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.initChownData.image.repository }}:{{ .Values.initChownData.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.initChownData.image.pullPolicy }} + {{- with .Values.initChownData.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + command: + - chown + - -R + - {{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.runAsGroup }} + - /var/lib/grafana + {{- with .Values.initChownData.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: storage + mountPath: "/var/lib/grafana" + {{- with .Values.persistence.subPath }} + subPath: {{ tpl . $root }} + {{- end }} +{{- end }} +{{- if .Values.dashboards }} + - name: download-dashboards + {{- $registry := include "system_default_registry" . | default .Values.downloadDashboardsImage.registry -}} + {{- if .Values.downloadDashboardsImage.sha }} + image: "{{ $registry }}{{ .Values.downloadDashboardsImage.repository }}:{{ .Values.downloadDashboardsImage.tag }}@sha256:{{ .Values.downloadDashboardsImage.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.downloadDashboardsImage.repository }}:{{ .Values.downloadDashboardsImage.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.downloadDashboardsImage.pullPolicy }} + command: ["/bin/sh"] + args: [ "-c", "mkdir -p /var/lib/grafana/dashboards/default && /bin/sh -x /etc/grafana/download_dashboards.sh" ] + {{- with .Values.downloadDashboards.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + env: + {{- range $key, $value := .Values.downloadDashboards.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- range $key, $value := .Values.downloadDashboards.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 10 }} + {{- end }} + {{- with .Values.downloadDashboards.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.downloadDashboards.envFromSecret }} + envFrom: + - secretRef: + name: {{ tpl . $root }} + {{- end }} + volumeMounts: + - name: config + mountPath: "/etc/grafana/download_dashboards.sh" + subPath: download_dashboards.sh + - name: storage + mountPath: "/var/lib/grafana" + {{- with .Values.persistence.subPath }} + subPath: {{ tpl . $root }} + {{- end }} + {{- range .Values.extraSecretMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: {{ .readOnly }} + {{- end }} +{{- end }} +{{- if and .Values.sidecar.alerts.enabled .Values.sidecar.alerts.initAlerts }} + - name: {{ include "grafana.name" . }}-init-sc-alerts + {{- $registry := include "system_default_registry" . | default .Values.sidecar.image.registry -}} + {{- if .Values.sidecar.image.sha }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }} + env: + {{- range $key, $value := .Values.sidecar.alerts.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- if .Values.sidecar.alerts.ignoreAlreadyProcessed }} + - name: IGNORE_ALREADY_PROCESSED + value: "true" + {{- end }} + - name: METHOD + value: "LIST" + - name: LABEL + value: "{{ .Values.sidecar.alerts.label }}" + {{- with .Values.sidecar.alerts.labelValue }} + - name: LABEL_VALUE + value: {{ quote . }} + {{- end }} + {{- if or .Values.sidecar.logLevel .Values.sidecar.alerts.logLevel }} + - name: LOG_LEVEL + value: {{ default .Values.sidecar.logLevel .Values.sidecar.alerts.logLevel }} + {{- end }} + - name: FOLDER + value: "/etc/grafana/provisioning/alerting" + - name: RESOURCE + value: {{ quote .Values.sidecar.alerts.resource }} + {{- with .Values.sidecar.enableUniqueFilenames }} + - name: UNIQUE_FILENAMES + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.alerts.searchNamespace }} + - name: NAMESPACE + value: {{ . | join "," | quote }} + {{- end }} + {{- with .Values.sidecar.alerts.skipTlsVerify }} + - name: SKIP_TLS_VERIFY + value: {{ quote . }} + {{- end }} + {{- with .Values.sidecar.alerts.script }} + - name: SCRIPT + value: {{ quote . }} + {{- end }} + {{- with .Values.sidecar.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: sc-alerts-volume + mountPath: "/etc/grafana/provisioning/alerting" + {{- with .Values.sidecar.alerts.extraMounts }} + {{- toYaml . | trim | nindent 6 }} + {{- end }} +{{- end }} +{{- if and .Values.sidecar.datasources.enabled .Values.sidecar.datasources.initDatasources }} + - name: {{ include "grafana.name" . }}-init-sc-datasources + {{- $registry := include "system_default_registry" . | default .Values.sidecar.image.registry -}} + {{- if .Values.sidecar.image.sha }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }} + env: + {{- range $key, $value := .Values.sidecar.datasources.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- range $key, $value := .Values.sidecar.datasources.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 10 }} + {{- end }} + {{- if .Values.sidecar.datasources.ignoreAlreadyProcessed }} + - name: IGNORE_ALREADY_PROCESSED + value: "true" + {{- end }} + - name: METHOD + value: "LIST" + - name: LABEL + value: "{{ .Values.sidecar.datasources.label }}" + {{- with .Values.sidecar.datasources.labelValue }} + - name: LABEL_VALUE + value: {{ quote . }} + {{- end }} + {{- if or .Values.sidecar.logLevel .Values.sidecar.datasources.logLevel }} + - name: LOG_LEVEL + value: {{ default .Values.sidecar.logLevel .Values.sidecar.datasources.logLevel }} + {{- end }} + - name: FOLDER + value: "/etc/grafana/provisioning/datasources" + - name: RESOURCE + value: {{ quote .Values.sidecar.datasources.resource }} + {{- with .Values.sidecar.enableUniqueFilenames }} + - name: UNIQUE_FILENAMES + value: "{{ . }}" + {{- end }} + {{- if .Values.sidecar.datasources.searchNamespace }} + - name: NAMESPACE + value: "{{ tpl (.Values.sidecar.datasources.searchNamespace | join ",") . }}" + {{- end }} + {{- with .Values.sidecar.skipTlsVerify }} + - name: SKIP_TLS_VERIFY + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: sc-datasources-volume + mountPath: "/etc/grafana/provisioning/datasources" +{{- end }} +{{- if and .Values.sidecar.notifiers.enabled .Values.sidecar.notifiers.initNotifiers }} + - name: {{ include "grafana.name" . }}-init-sc-notifiers + {{- $registry := include "system_default_registry" . | default .Values.sidecar.image.registry -}} + {{- if .Values.sidecar.image.sha }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }} + env: + {{- range $key, $value := .Values.sidecar.notifiers.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- if .Values.sidecar.notifiers.ignoreAlreadyProcessed }} + - name: IGNORE_ALREADY_PROCESSED + value: "true" + {{- end }} + - name: METHOD + value: LIST + - name: LABEL + value: "{{ .Values.sidecar.notifiers.label }}" + {{- with .Values.sidecar.notifiers.labelValue }} + - name: LABEL_VALUE + value: {{ quote . }} + {{- end }} + {{- if or .Values.sidecar.logLevel .Values.sidecar.notifiers.logLevel }} + - name: LOG_LEVEL + value: {{ default .Values.sidecar.logLevel .Values.sidecar.notifiers.logLevel }} + {{- end }} + - name: FOLDER + value: "/etc/grafana/provisioning/notifiers" + - name: RESOURCE + value: {{ quote .Values.sidecar.notifiers.resource }} + {{- with .Values.sidecar.enableUniqueFilenames }} + - name: UNIQUE_FILENAMES + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.notifiers.searchNamespace }} + - name: NAMESPACE + value: "{{ tpl (. | join ",") $root }}" + {{- end }} + {{- with .Values.sidecar.skipTlsVerify }} + - name: SKIP_TLS_VERIFY + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: sc-notifiers-volume + mountPath: "/etc/grafana/provisioning/notifiers" +{{- end}} +{{- with .Values.extraInitContainers }} + {{- tpl (toYaml .) $root | nindent 2 }} +{{- end }} +{{- if or .Values.image.pullSecrets .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- include "grafana.imagePullSecrets" (dict "root" $root "imagePullSecrets" .Values.image.pullSecrets) | nindent 2 }} +{{- end }} +{{- if not .Values.enableKubeBackwardCompatibility }} +enableServiceLinks: {{ .Values.enableServiceLinks }} +{{- end }} +containers: +{{- if and .Values.sidecar.alerts.enabled (not .Values.sidecar.alerts.initAlerts) }} + - name: {{ include "grafana.name" . }}-sc-alerts + {{- $registry := include "system_default_registry" . | default .Values.sidecar.image.registry -}} + {{- if .Values.sidecar.image.sha }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }} + env: + {{- range $key, $value := .Values.sidecar.alerts.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- if .Values.sidecar.alerts.ignoreAlreadyProcessed }} + - name: IGNORE_ALREADY_PROCESSED + value: "true" + {{- end }} + - name: METHOD + value: {{ .Values.sidecar.alerts.watchMethod }} + - name: LABEL + value: "{{ .Values.sidecar.alerts.label }}" + {{- with .Values.sidecar.alerts.labelValue }} + - name: LABEL_VALUE + value: {{ quote . }} + {{- end }} + {{- if or .Values.sidecar.logLevel .Values.sidecar.alerts.logLevel }} + - name: LOG_LEVEL + value: {{ default .Values.sidecar.logLevel .Values.sidecar.alerts.logLevel }} + {{- end }} + - name: FOLDER + value: "/etc/grafana/provisioning/alerting" + - name: RESOURCE + value: {{ quote .Values.sidecar.alerts.resource }} + {{- with .Values.sidecar.enableUniqueFilenames }} + - name: UNIQUE_FILENAMES + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.alerts.searchNamespace }} + - name: NAMESPACE + value: {{ . | join "," | quote }} + {{- end }} + {{- with .Values.sidecar.alerts.skipTlsVerify }} + - name: SKIP_TLS_VERIFY + value: {{ quote . }} + {{- end }} + {{- with .Values.sidecar.alerts.script }} + - name: SCRIPT + value: {{ quote . }} + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_USERNAME + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.userKey | default "admin-user" }} + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_PASSWORD + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.passwordKey | default "admin-password" }} + {{- end }} + {{- if not .Values.sidecar.alerts.skipReload }} + - name: REQ_URL + value: {{ .Values.sidecar.alerts.reloadURL }} + - name: REQ_METHOD + value: POST + {{- end }} + {{- if .Values.sidecar.alerts.watchServerTimeout }} + {{- if ne .Values.sidecar.alerts.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.alerts.watchServerTimeout with .Values.sidecar.alerts.watchMethod %s" .Values.sidecar.alerts.watchMethod) }} + {{- end }} + - name: WATCH_SERVER_TIMEOUT + value: "{{ .Values.sidecar.alerts.watchServerTimeout }}" + {{- end }} + {{- if .Values.sidecar.alerts.watchClientTimeout }} + {{- if ne .Values.sidecar.alerts.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.alerts.watchClientTimeout with .Values.sidecar.alerts.watchMethod %s" .Values.sidecar.alerts.watchMethod) }} + {{- end }} + - name: WATCH_CLIENT_TIMEOUT + value: "{{ .Values.sidecar.alerts.watchClientTimeout }}" + {{- end }} + {{- with .Values.sidecar.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: sc-alerts-volume + mountPath: "/etc/grafana/provisioning/alerting" + {{- with .Values.sidecar.alerts.extraMounts }} + {{- toYaml . | trim | nindent 6 }} + {{- end }} +{{- end}} +{{- if .Values.sidecar.dashboards.enabled }} + - name: {{ include "grafana.name" . }}-sc-dashboard + {{- $registry := include "system_default_registry" . | default .Values.sidecar.image.registry -}} + {{- if .Values.sidecar.image.sha }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }} + env: + {{- range $key, $value := .Values.sidecar.dashboards.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- range $key, $value := .Values.sidecar.dashboards.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 10 }} + {{- end }} + {{- if .Values.sidecar.dashboards.ignoreAlreadyProcessed }} + - name: IGNORE_ALREADY_PROCESSED + value: "true" + {{- end }} + - name: METHOD + value: {{ .Values.sidecar.dashboards.watchMethod }} + - name: LABEL + value: "{{ .Values.sidecar.dashboards.label }}" + {{- with .Values.sidecar.dashboards.labelValue }} + - name: LABEL_VALUE + value: {{ quote . }} + {{- end }} + {{- if or .Values.sidecar.logLevel .Values.sidecar.dashboards.logLevel }} + - name: LOG_LEVEL + value: {{ default .Values.sidecar.logLevel .Values.sidecar.dashboards.logLevel }} + {{- end }} + - name: FOLDER + value: "{{ .Values.sidecar.dashboards.folder }}{{- with .Values.sidecar.dashboards.defaultFolderName }}/{{ . }}{{- end }}" + - name: RESOURCE + value: {{ quote .Values.sidecar.dashboards.resource }} + {{- with .Values.sidecar.enableUniqueFilenames }} + - name: UNIQUE_FILENAMES + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.dashboards.searchNamespace }} + - name: NAMESPACE + value: "{{ tpl (. | join ",") $root }}" + {{- end }} + {{- with .Values.sidecar.skipTlsVerify }} + - name: SKIP_TLS_VERIFY + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.dashboards.folderAnnotation }} + - name: FOLDER_ANNOTATION + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.dashboards.script }} + - name: SCRIPT + value: "{{ . }}" + {{- end }} + {{- if not .Values.sidecar.dashboards.skipReload }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_USERNAME + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.userKey | default "admin-user" }} + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_PASSWORD + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.passwordKey | default "admin-password" }} + {{- end }} + - name: REQ_URL + value: {{ .Values.sidecar.dashboards.reloadURL }} + - name: REQ_METHOD + value: POST + {{- end }} + {{- if .Values.sidecar.dashboards.watchServerTimeout }} + {{- if ne .Values.sidecar.dashboards.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.dashboards.watchServerTimeout with .Values.sidecar.dashboards.watchMethod %s" .Values.sidecar.dashboards.watchMethod) }} + {{- end }} + - name: WATCH_SERVER_TIMEOUT + value: "{{ .Values.sidecar.dashboards.watchServerTimeout }}" + {{- end }} + {{- if .Values.sidecar.dashboards.watchClientTimeout }} + {{- if ne .Values.sidecar.dashboards.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.dashboards.watchClientTimeout with .Values.sidecar.dashboards.watchMethod %s" .Values.sidecar.dashboards.watchMethod) }} + {{- end }} + - name: WATCH_CLIENT_TIMEOUT + value: {{ .Values.sidecar.dashboards.watchClientTimeout | quote }} + {{- end }} + {{- with .Values.sidecar.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: sc-dashboard-volume + mountPath: {{ .Values.sidecar.dashboards.folder | quote }} + {{- with .Values.sidecar.dashboards.extraMounts }} + {{- toYaml . | trim | nindent 6 }} + {{- end }} +{{- end}} +{{- if and .Values.sidecar.datasources.enabled (not .Values.sidecar.datasources.initDatasources) }} + - name: {{ include "grafana.name" . }}-sc-datasources + {{- $registry := include "system_default_registry" . | default .Values.sidecar.image.registry -}} + {{- if .Values.sidecar.image.sha }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }} + env: + {{- range $key, $value := .Values.sidecar.datasources.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- range $key, $value := .Values.sidecar.datasources.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 10 }} + {{- end }} + {{- if .Values.sidecar.datasources.ignoreAlreadyProcessed }} + - name: IGNORE_ALREADY_PROCESSED + value: "true" + {{- end }} + - name: METHOD + value: {{ .Values.sidecar.datasources.watchMethod }} + - name: LABEL + value: "{{ .Values.sidecar.datasources.label }}" + {{- with .Values.sidecar.datasources.labelValue }} + - name: LABEL_VALUE + value: {{ quote . }} + {{- end }} + {{- if or .Values.sidecar.logLevel .Values.sidecar.datasources.logLevel }} + - name: LOG_LEVEL + value: {{ default .Values.sidecar.logLevel .Values.sidecar.datasources.logLevel }} + {{- end }} + - name: FOLDER + value: "/etc/grafana/provisioning/datasources" + - name: RESOURCE + value: {{ quote .Values.sidecar.datasources.resource }} + {{- with .Values.sidecar.enableUniqueFilenames }} + - name: UNIQUE_FILENAMES + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.datasources.searchNamespace }} + - name: NAMESPACE + value: "{{ tpl (. | join ",") $root }}" + {{- end }} + {{- if .Values.sidecar.skipTlsVerify }} + - name: SKIP_TLS_VERIFY + value: "{{ .Values.sidecar.skipTlsVerify }}" + {{- end }} + {{- if .Values.sidecar.datasources.script }} + - name: SCRIPT + value: "{{ .Values.sidecar.datasources.script }}" + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_USERNAME + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.userKey | default "admin-user" }} + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_PASSWORD + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.passwordKey | default "admin-password" }} + {{- end }} + {{- if not .Values.sidecar.datasources.skipReload }} + - name: REQ_URL + value: {{ .Values.sidecar.datasources.reloadURL }} + - name: REQ_METHOD + value: POST + {{- end }} + {{- if .Values.sidecar.datasources.watchServerTimeout }} + {{- if ne .Values.sidecar.datasources.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.datasources.watchServerTimeout with .Values.sidecar.datasources.watchMethod %s" .Values.sidecar.datasources.watchMethod) }} + {{- end }} + - name: WATCH_SERVER_TIMEOUT + value: "{{ .Values.sidecar.datasources.watchServerTimeout }}" + {{- end }} + {{- if .Values.sidecar.datasources.watchClientTimeout }} + {{- if ne .Values.sidecar.datasources.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.datasources.watchClientTimeout with .Values.sidecar.datasources.watchMethod %s" .Values.sidecar.datasources.watchMethod) }} + {{- end }} + - name: WATCH_CLIENT_TIMEOUT + value: "{{ .Values.sidecar.datasources.watchClientTimeout }}" + {{- end }} + {{- with .Values.sidecar.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: sc-datasources-volume + mountPath: "/etc/grafana/provisioning/datasources" +{{- end}} +{{- if .Values.sidecar.notifiers.enabled }} + - name: {{ include "grafana.name" . }}-sc-notifiers + {{- $registry := include "system_default_registry" . | default .Values.sidecar.image.registry -}} + {{- if .Values.sidecar.image.sha }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }} + env: + {{- range $key, $value := .Values.sidecar.notifiers.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- if .Values.sidecar.notifiers.ignoreAlreadyProcessed }} + - name: IGNORE_ALREADY_PROCESSED + value: "true" + {{- end }} + - name: METHOD + value: {{ .Values.sidecar.notifiers.watchMethod }} + - name: LABEL + value: "{{ .Values.sidecar.notifiers.label }}" + {{- with .Values.sidecar.notifiers.labelValue }} + - name: LABEL_VALUE + value: {{ quote . }} + {{- end }} + {{- if or .Values.sidecar.logLevel .Values.sidecar.notifiers.logLevel }} + - name: LOG_LEVEL + value: {{ default .Values.sidecar.logLevel .Values.sidecar.notifiers.logLevel }} + {{- end }} + - name: FOLDER + value: "/etc/grafana/provisioning/notifiers" + - name: RESOURCE + value: {{ quote .Values.sidecar.notifiers.resource }} + {{- if .Values.sidecar.enableUniqueFilenames }} + - name: UNIQUE_FILENAMES + value: "{{ .Values.sidecar.enableUniqueFilenames }}" + {{- end }} + {{- with .Values.sidecar.notifiers.searchNamespace }} + - name: NAMESPACE + value: "{{ tpl (. | join ",") $root }}" + {{- end }} + {{- with .Values.sidecar.skipTlsVerify }} + - name: SKIP_TLS_VERIFY + value: "{{ . }}" + {{- end }} + {{- if .Values.sidecar.notifiers.script }} + - name: SCRIPT + value: "{{ .Values.sidecar.notifiers.script }}" + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_USERNAME + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.userKey | default "admin-user" }} + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_PASSWORD + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.passwordKey | default "admin-password" }} + {{- end }} + {{- if not .Values.sidecar.notifiers.skipReload }} + - name: REQ_URL + value: {{ .Values.sidecar.notifiers.reloadURL }} + - name: REQ_METHOD + value: POST + {{- end }} + {{- if .Values.sidecar.notifiers.watchServerTimeout }} + {{- if ne .Values.sidecar.notifiers.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.notifiers.watchServerTimeout with .Values.sidecar.notifiers.watchMethod %s" .Values.sidecar.notifiers.watchMethod) }} + {{- end }} + - name: WATCH_SERVER_TIMEOUT + value: "{{ .Values.sidecar.notifiers.watchServerTimeout }}" + {{- end }} + {{- if .Values.sidecar.notifiers.watchClientTimeout }} + {{- if ne .Values.sidecar.notifiers.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.notifiers.watchClientTimeout with .Values.sidecar.notifiers.watchMethod %s" .Values.sidecar.notifiers.watchMethod) }} + {{- end }} + - name: WATCH_CLIENT_TIMEOUT + value: "{{ .Values.sidecar.notifiers.watchClientTimeout }}" + {{- end }} + {{- with .Values.sidecar.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: sc-notifiers-volume + mountPath: "/etc/grafana/provisioning/notifiers" +{{- end}} +{{- if .Values.sidecar.plugins.enabled }} + - name: {{ include "grafana.name" . }}-sc-plugins + {{- $registry := include "system_default_registry" . | default .Values.sidecar.image.registry -}} + {{- if .Values.sidecar.image.sha }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}@sha256:{{ .Values.sidecar.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.sidecar.image.repository }}:{{ .Values.sidecar.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.sidecar.imagePullPolicy }} + env: + {{- range $key, $value := .Values.sidecar.plugins.env }} + - name: "{{ $key }}" + value: "{{ $value }}" + {{- end }} + {{- if .Values.sidecar.plugins.ignoreAlreadyProcessed }} + - name: IGNORE_ALREADY_PROCESSED + value: "true" + {{- end }} + - name: METHOD + value: {{ .Values.sidecar.plugins.watchMethod }} + - name: LABEL + value: "{{ .Values.sidecar.plugins.label }}" + {{- if .Values.sidecar.plugins.labelValue }} + - name: LABEL_VALUE + value: {{ quote .Values.sidecar.plugins.labelValue }} + {{- end }} + {{- if or .Values.sidecar.logLevel .Values.sidecar.plugins.logLevel }} + - name: LOG_LEVEL + value: {{ default .Values.sidecar.logLevel .Values.sidecar.plugins.logLevel }} + {{- end }} + - name: FOLDER + value: "/etc/grafana/provisioning/plugins" + - name: RESOURCE + value: {{ quote .Values.sidecar.plugins.resource }} + {{- with .Values.sidecar.enableUniqueFilenames }} + - name: UNIQUE_FILENAMES + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.plugins.searchNamespace }} + - name: NAMESPACE + value: "{{ tpl (. | join ",") $root }}" + {{- end }} + {{- with .Values.sidecar.plugins.script }} + - name: SCRIPT + value: "{{ . }}" + {{- end }} + {{- with .Values.sidecar.skipTlsVerify }} + - name: SKIP_TLS_VERIFY + value: "{{ . }}" + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_USERNAME + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.userKey | default "admin-user" }} + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: REQ_PASSWORD + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.passwordKey | default "admin-password" }} + {{- end }} + {{- if not .Values.sidecar.plugins.skipReload }} + - name: REQ_URL + value: {{ .Values.sidecar.plugins.reloadURL }} + - name: REQ_METHOD + value: POST + {{- end }} + {{- if .Values.sidecar.plugins.watchServerTimeout }} + {{- if ne .Values.sidecar.plugins.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.plugins.watchServerTimeout with .Values.sidecar.plugins.watchMethod %s" .Values.sidecar.plugins.watchMethod) }} + {{- end }} + - name: WATCH_SERVER_TIMEOUT + value: "{{ .Values.sidecar.plugins.watchServerTimeout }}" + {{- end }} + {{- if .Values.sidecar.plugins.watchClientTimeout }} + {{- if ne .Values.sidecar.plugins.watchMethod "WATCH" }} + {{- fail (printf "Cannot use .Values.sidecar.plugins.watchClientTimeout with .Values.sidecar.plugins.watchMethod %s" .Values.sidecar.plugins.watchMethod) }} + {{- end }} + - name: WATCH_CLIENT_TIMEOUT + value: "{{ .Values.sidecar.plugins.watchClientTimeout }}" + {{- end }} + {{- with .Values.sidecar.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.sidecar.securityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: sc-plugins-volume + mountPath: "/etc/grafana/provisioning/plugins" +{{- end}} + - name: {{ .Chart.Name }} + {{- $registry := include "system_default_registry" . | default .Values.image.registry -}} + {{- if .Values.image.sha }} + image: "{{ $registry }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}@sha256:{{ .Values.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + {{- end }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.command }} + command: + {{- range .Values.command }} + - {{ . | quote }} + {{- end }} + {{- end }} + {{- if .Values.args }} + args: + {{- range .Values.args }} + - {{ . | quote }} + {{- end }} + {{- end }} + {{- with .Values.containerSecurityContext }} + securityContext: + {{- toYaml . | nindent 6 }} + {{- end }} + volumeMounts: + - name: config + mountPath: "/etc/grafana/grafana.ini" + subPath: grafana.ini + {{- if .Values.ldap.enabled }} + - name: ldap + mountPath: "/etc/grafana/ldap.toml" + subPath: ldap.toml + {{- end }} + {{- range .Values.extraConfigmapMounts }} + - name: {{ tpl .name $root }} + mountPath: {{ tpl .mountPath $root }} + subPath: {{ tpl (.subPath | default "") $root }} + readOnly: {{ .readOnly }} + {{- end }} + - name: storage + mountPath: "/var/lib/grafana" + {{- with .Values.persistence.subPath }} + subPath: {{ tpl . $root }} + {{- end }} + {{- with .Values.dashboards }} + {{- range $provider, $dashboards := . }} + {{- range $key, $value := $dashboards }} + {{- if (or (hasKey $value "json") (hasKey $value "file")) }} + - name: dashboards-{{ $provider }} + mountPath: "/var/lib/grafana/dashboards/{{ $provider }}/{{ $key }}.json" + subPath: "{{ $key }}.json" + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.dashboardsConfigMaps }} + {{- range (keys . | sortAlpha) }} + - name: dashboards-{{ . }} + mountPath: "/var/lib/grafana/dashboards/{{ . }}" + {{- end }} + {{- end }} + {{- with .Values.datasources }} + {{- $datasources := . }} + {{- range (keys . | sortAlpha) }} + {{- if (or (hasKey (index $datasources .) "secret")) }} {{/*check if current datasource should be handeled as secret */}} + - name: config-secret + mountPath: "/etc/grafana/provisioning/datasources/{{ . }}" + subPath: {{ . | quote }} + {{- else }} + - name: config + mountPath: "/etc/grafana/provisioning/datasources/{{ . }}" + subPath: {{ . | quote }} + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.notifiers }} + {{- $notifiers := . }} + {{- range (keys . | sortAlpha) }} + {{- if (or (hasKey (index $notifiers .) "secret")) }} {{/*check if current notifier should be handeled as secret */}} + - name: config-secret + mountPath: "/etc/grafana/provisioning/notifiers/{{ . }}" + subPath: {{ . | quote }} + {{- else }} + - name: config + mountPath: "/etc/grafana/provisioning/notifiers/{{ . }}" + subPath: {{ . | quote }} + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.alerting }} + {{- $alertingmap := .}} + {{- range (keys . | sortAlpha) }} + {{- if (or (hasKey (index $.Values.alerting .) "secret") (hasKey (index $.Values.alerting .) "secretFile")) }} {{/*check if current alerting entry should be handeled as secret */}} + - name: config-secret + mountPath: "/etc/grafana/provisioning/alerting/{{ . }}" + subPath: {{ . | quote }} + {{- else }} + - name: config + mountPath: "/etc/grafana/provisioning/alerting/{{ . }}" + subPath: {{ . | quote }} + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.dashboardProviders }} + {{- range (keys . | sortAlpha) }} + - name: config + mountPath: "/etc/grafana/provisioning/dashboards/{{ . }}" + subPath: {{ . | quote }} + {{- end }} + {{- end }} + {{- with .Values.sidecar.alerts.enabled }} + - name: sc-alerts-volume + mountPath: "/etc/grafana/provisioning/alerting" + {{- end}} + {{- if .Values.sidecar.dashboards.enabled }} + - name: sc-dashboard-volume + mountPath: {{ .Values.sidecar.dashboards.folder | quote }} + {{- if .Values.sidecar.dashboards.SCProvider }} + - name: sc-dashboard-provider + mountPath: "/etc/grafana/provisioning/dashboards/sc-dashboardproviders.yaml" + subPath: provider.yaml + {{- end}} + {{- end}} + {{- if .Values.sidecar.datasources.enabled }} + - name: sc-datasources-volume + mountPath: "/etc/grafana/provisioning/datasources" + {{- end}} + {{- if .Values.sidecar.plugins.enabled }} + - name: sc-plugins-volume + mountPath: "/etc/grafana/provisioning/plugins" + {{- end}} + {{- if .Values.sidecar.notifiers.enabled }} + - name: sc-notifiers-volume + mountPath: "/etc/grafana/provisioning/notifiers" + {{- end}} + {{- range .Values.extraSecretMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: {{ .readOnly }} + subPath: {{ .subPath | default "" }} + {{- end }} + {{- range .Values.extraVolumeMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + subPath: {{ .subPath | default "" }} + readOnly: {{ .readOnly }} + {{- end }} + {{- range .Values.extraEmptyDirMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + {{- end }} + ports: + - name: {{ .Values.podPortName }} + containerPort: {{ .Values.service.targetPort }} + protocol: TCP + - name: {{ .Values.gossipPortName }}-tcp + containerPort: 9094 + protocol: TCP + - name: {{ .Values.gossipPortName }}-udp + containerPort: 9094 + protocol: UDP + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + {{- if and (not .Values.env.GF_SECURITY_ADMIN_USER) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: GF_SECURITY_ADMIN_USER + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.userKey | default "admin-user" }} + {{- end }} + {{- if and (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + - name: GF_SECURITY_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: {{ (tpl .Values.admin.existingSecret .) | default (include "grafana.fullname" .) }} + key: {{ .Values.admin.passwordKey | default "admin-password" }} + {{- end }} + {{- if .Values.plugins }} + - name: GF_INSTALL_PLUGINS + valueFrom: + configMapKeyRef: + name: {{ include "grafana.fullname" . }} + key: plugins + {{- end }} + {{- if .Values.smtp.existingSecret }} + - name: GF_SMTP_USER + valueFrom: + secretKeyRef: + name: {{ .Values.smtp.existingSecret }} + key: {{ .Values.smtp.userKey | default "user" }} + - name: GF_SMTP_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.smtp.existingSecret }} + key: {{ .Values.smtp.passwordKey | default "password" }} + {{- end }} + {{- if .Values.imageRenderer.enabled }} + - name: GF_RENDERING_SERVER_URL + value: http://{{ include "grafana.fullname" . }}-image-renderer.{{ include "grafana.namespace" . }}:{{ .Values.imageRenderer.service.port }}/render + - name: GF_RENDERING_CALLBACK_URL + value: {{ .Values.imageRenderer.grafanaProtocol }}://{{ include "grafana.fullname" . }}.{{ include "grafana.namespace" . }}:{{ .Values.service.port }}/{{ .Values.imageRenderer.grafanaSubPath }} + {{- end }} + - name: GF_PATHS_DATA + value: {{ (get .Values "grafana.ini").paths.data }} + - name: GF_PATHS_LOGS + value: {{ (get .Values "grafana.ini").paths.logs }} + - name: GF_PATHS_PLUGINS + value: {{ (get .Values "grafana.ini").paths.plugins }} + - name: GF_PATHS_PROVISIONING + value: {{ (get .Values "grafana.ini").paths.provisioning }} + {{- range $key, $value := .Values.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 10 }} + {{- end }} + {{- range $key, $value := .Values.env }} + - name: "{{ tpl $key $ }}" + value: "{{ tpl (print $value) $ }}" + {{- end }} + {{- if or .Values.envFromSecret (or .Values.envRenderSecret .Values.envFromSecrets) .Values.envFromConfigMaps }} + envFrom: + {{- if .Values.envFromSecret }} + - secretRef: + name: {{ tpl .Values.envFromSecret . }} + {{- end }} + {{- if .Values.envRenderSecret }} + - secretRef: + name: {{ include "grafana.fullname" . }}-env + {{- end }} + {{- range .Values.envFromSecrets }} + - secretRef: + name: {{ tpl .name $ }} + optional: {{ .optional | default false }} + {{- if .prefix }} + prefix: {{ tpl .prefix $ }} + {{- end }} + {{- end }} + {{- range .Values.envFromConfigMaps }} + - configMapRef: + name: {{ tpl .name $ }} + optional: {{ .optional | default false }} + {{- if .prefix }} + prefix: {{ tpl .prefix $ }} + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.lifecycleHooks }} + lifecycle: + {{- tpl (toYaml .) $root | nindent 6 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- with .Values.extraContainers }} + {{- tpl . $ | nindent 2 }} +{{- end }} +nodeSelector: {{ include "linux-node-selector" . | nindent 2 }} +{{- with .Values.nodeSelector }} + {{- toYaml . | nindent 2 }} +{{- end }} +{{- with .Values.affinity }} +affinity: + {{- tpl (toYaml .) $root | nindent 2 }} +{{- end }} +{{- with .Values.topologySpreadConstraints }} +topologySpreadConstraints: + {{- toYaml . | nindent 2 }} +{{- end }} +tolerations: {{ include "linux-node-tolerations" . | nindent 2 }} +{{- with .Values.tolerations }} + {{- toYaml . | nindent 2 }} +{{- end }} +volumes: + - name: config + configMap: + name: {{ include "grafana.fullname" . }} + {{- $createConfigSecret := eq (include "grafana.shouldCreateConfigSecret" .) "true" -}} + {{- if and .Values.createConfigmap $createConfigSecret }} + - name: config-secret + secret: + secretName: {{ include "grafana.fullname" . }}-config-secret + {{- end }} + {{- range .Values.extraConfigmapMounts }} + - name: {{ tpl .name $root }} + configMap: + name: {{ tpl .configMap $root }} + {{- with .items }} + items: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.dashboards }} + {{- range (keys .Values.dashboards | sortAlpha) }} + - name: dashboards-{{ . }} + configMap: + name: {{ include "grafana.fullname" $ }}-dashboards-{{ . }} + {{- end }} + {{- end }} + {{- if .Values.dashboardsConfigMaps }} + {{- range $provider, $name := .Values.dashboardsConfigMaps }} + - name: dashboards-{{ $provider }} + configMap: + name: {{ tpl $name $root }} + {{- end }} + {{- end }} + {{- if .Values.ldap.enabled }} + - name: ldap + secret: + {{- if .Values.ldap.existingSecret }} + secretName: {{ .Values.ldap.existingSecret }} + {{- else }} + secretName: {{ include "grafana.fullname" . }} + {{- end }} + items: + - key: ldap-toml + path: ldap.toml + {{- end }} + {{- if and .Values.persistence.enabled (eq .Values.persistence.type "pvc") }} + - name: storage + persistentVolumeClaim: + claimName: {{ tpl (.Values.persistence.existingClaim | default (include "grafana.fullname" .)) . }} + {{- else if and .Values.persistence.enabled (has .Values.persistence.type $sts) }} + {{/* nothing */}} + {{- else }} + - name: storage + {{- if .Values.persistence.inMemory.enabled }} + emptyDir: + medium: Memory + {{- with .Values.persistence.inMemory.sizeLimit }} + sizeLimit: {{ . }} + {{- end }} + {{- else }} + emptyDir: {} + {{- end }} + {{- end }} + {{- if .Values.sidecar.alerts.enabled }} + - name: sc-alerts-volume + emptyDir: + {{- with .Values.sidecar.alerts.sizeLimit }} + sizeLimit: {{ . }} + {{- else }} + {} + {{- end }} + {{- end }} + {{- if .Values.sidecar.dashboards.enabled }} + - name: sc-dashboard-volume + emptyDir: + {{- with .Values.sidecar.dashboards.sizeLimit }} + sizeLimit: {{ . }} + {{- else }} + {} + {{- end }} + {{- if .Values.sidecar.dashboards.SCProvider }} + - name: sc-dashboard-provider + configMap: + name: {{ include "grafana.fullname" . }}-config-dashboards + {{- end }} + {{- end }} + {{- if .Values.sidecar.datasources.enabled }} + - name: sc-datasources-volume + emptyDir: + {{- with .Values.sidecar.datasources.sizeLimit }} + sizeLimit: {{ . }} + {{- else }} + {} + {{- end }} + {{- end }} + {{- if .Values.sidecar.plugins.enabled }} + - name: sc-plugins-volume + emptyDir: + {{- with .Values.sidecar.plugins.sizeLimit }} + sizeLimit: {{ . }} + {{- else }} + {} + {{- end }} + {{- end }} + {{- if .Values.sidecar.notifiers.enabled }} + - name: sc-notifiers-volume + emptyDir: + {{- with .Values.sidecar.notifiers.sizeLimit }} + sizeLimit: {{ . }} + {{- else }} + {} + {{- end }} + {{- end }} + {{- range .Values.extraSecretMounts }} + {{- if .secretName }} + - name: {{ .name }} + secret: + secretName: {{ .secretName }} + defaultMode: {{ .defaultMode }} + {{- with .items }} + items: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- else if .projected }} + - name: {{ .name }} + projected: + {{- toYaml .projected | nindent 6 }} + {{- else if .csi }} + - name: {{ .name }} + csi: + {{- toYaml .csi | nindent 6 }} + {{- end }} + {{- end }} + {{- range .Values.extraVolumes }} + - name: {{ .name }} + {{- if .existingClaim }} + persistentVolumeClaim: + claimName: {{ .existingClaim }} + {{- else if .hostPath }} + hostPath: + {{ toYaml .hostPath | nindent 6 }} + {{- else if .csi }} + csi: + {{- toYaml .csi | nindent 6 }} + {{- else if .configMap }} + configMap: + {{- toYaml .configMap | nindent 6 }} + {{- else if .emptyDir }} + emptyDir: + {{- toYaml .emptyDir | nindent 6 }} + {{- else }} + emptyDir: {} + {{- end }} + {{- end }} + {{- range .Values.extraEmptyDirMounts }} + - name: {{ .name }} + emptyDir: {} + {{- end }} + {{- with .Values.extraContainerVolumes }} + {{- tpl (toYaml .) $root | nindent 2 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/clusterrole.yaml new file mode 100644 index 0000000000..3af4b62b63 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/clusterrole.yaml @@ -0,0 +1,25 @@ +{{- if and .Values.rbac.create (or (not .Values.rbac.namespaced) .Values.rbac.extraClusterRoleRules) (not .Values.rbac.useExistingClusterRole) }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + name: {{ include "grafana.fullname" . }}-clusterrole +{{- if or .Values.sidecar.dashboards.enabled .Values.rbac.extraClusterRoleRules .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled .Values.sidecar.alerts.enabled }} +rules: + {{- if or .Values.sidecar.dashboards.enabled .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled .Values.sidecar.alerts.enabled }} + - apiGroups: [""] # "" indicates the core API group + resources: ["configmaps", "secrets"] + verbs: ["get", "watch", "list"] + {{- end}} + {{- with .Values.rbac.extraClusterRoleRules }} + {{- toYaml . | nindent 2 }} + {{- end}} +{{- else }} +rules: [] +{{- end}} +{{- end}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/clusterrolebinding.yaml new file mode 100644 index 0000000000..bda9431a2c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/clusterrolebinding.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.rbac.create (or (not .Values.rbac.namespaced) .Values.rbac.extraClusterRoleRules) }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ include "grafana.fullname" . }}-clusterrolebinding + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +subjects: + - kind: ServiceAccount + name: {{ include "grafana.serviceAccountName" . }} + namespace: {{ include "grafana.namespace" . }} +roleRef: + kind: ClusterRole + {{- if .Values.rbac.useExistingClusterRole }} + name: {{ .Values.rbac.useExistingClusterRole }} + {{- else }} + name: {{ include "grafana.fullname" . }}-clusterrole + {{- end }} + apiGroup: rbac.authorization.k8s.io +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configSecret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configSecret.yaml new file mode 100644 index 0000000000..55574b9bbc --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configSecret.yaml @@ -0,0 +1,43 @@ +{{- $createConfigSecret := eq (include "grafana.shouldCreateConfigSecret" .) "true" -}} +{{- if and .Values.createConfigmap $createConfigSecret }} +{{- $files := .Files }} +{{- $root := . -}} +apiVersion: v1 +kind: Secret +metadata: + name: "{{ include "grafana.fullname" . }}-config-secret" + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: +{{- range $key, $value := .Values.alerting }} + {{- if (hasKey $value "secretFile") }} + {{- $key | nindent 2 }}: + {{- toYaml ( $files.Get $value.secretFile ) | b64enc | nindent 4}} + {{/* as of https://helm.sh/docs/chart_template_guide/accessing_files/ this will only work if you fork this chart and add files to it*/}} + {{- end }} +{{- end }} +stringData: +{{- range $key, $value := .Values.datasources }} +{{- if (hasKey $value "secret") }} +{{- $key | nindent 2 }}: | + {{- tpl (toYaml $value.secret | nindent 4) $root }} +{{- end }} +{{- end }} +{{- range $key, $value := .Values.notifiers }} +{{- if (hasKey $value "secret") }} +{{- $key | nindent 2 }}: | + {{- tpl (toYaml $value.secret | nindent 4) $root }} +{{- end }} +{{- end }} +{{- range $key, $value := .Values.alerting }} +{{ if (hasKey $value "secret") }} + {{- $key | nindent 2 }}: | + {{- tpl (toYaml $value.secret | nindent 4) $root }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configmap-dashboard-provider.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configmap-dashboard-provider.yaml new file mode 100644 index 0000000000..b412c4d1f0 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configmap-dashboard-provider.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.sidecar.dashboards.enabled .Values.sidecar.dashboards.SCProvider }} +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + name: {{ include "grafana.fullname" . }}-config-dashboards + namespace: {{ include "grafana.namespace" . }} +data: + {{- include "grafana.configDashboardProviderData" . | nindent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configmap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configmap.yaml new file mode 100644 index 0000000000..0a2edf47e3 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/configmap.yaml @@ -0,0 +1,20 @@ +{{- if .Values.createConfigmap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- if or .Values.configMapAnnotations .Values.annotations }} + annotations: + {{- with .Values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.configMapAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +data: + {{- include "grafana.configData" . | nindent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/dashboards-json-configmap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/dashboards-json-configmap.yaml new file mode 100644 index 0000000000..b96ce72026 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/dashboards-json-configmap.yaml @@ -0,0 +1,38 @@ +{{- if .Values.dashboards }} +{{ $files := .Files }} +{{- range $provider, $dashboards := .Values.dashboards }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "grafana.fullname" $ }}-dashboards-{{ $provider }} + namespace: {{ include "grafana.namespace" $ }} + labels: + {{- include "grafana.labels" $ | nindent 4 }} + dashboard-provider: {{ $provider }} + {{- if $.Values.sidecar.dashboards.enabled }} + {{ $.Values.sidecar.dashboards.label }}: {{ $.Values.sidecar.dashboards.labelValue | quote }} + {{- end }} +{{- if $dashboards }} +data: +{{- $dashboardFound := false }} +{{- range $key, $value := $dashboards }} +{{- if (or (hasKey $value "json") (hasKey $value "file")) }} +{{- $dashboardFound = true }} + {{- print $key | nindent 2 }}.json: + {{- if hasKey $value "json" }} + |- + {{- $value.json | nindent 6 }} + {{- end }} + {{- if hasKey $value "file" }} + {{- toYaml ( $files.Get $value.file ) | nindent 4}} + {{- end }} +{{- end }} +{{- end }} +{{- if not $dashboardFound }} + {} +{{- end }} +{{- end }} +--- +{{- end }} + +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/deployment.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/deployment.yaml new file mode 100644 index 0000000000..46c016faa3 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/deployment.yaml @@ -0,0 +1,53 @@ +{{- if (and (not .Values.useStatefulSet) (or (not .Values.persistence.enabled) (eq .Values.persistence.type "pvc"))) }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and (not .Values.autoscaling.enabled) (.Values.replicas) }} + replicas: {{ .Values.replicas }} + {{- end }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + selector: + matchLabels: + {{- include "grafana.selectorLabels" . | nindent 6 }} + {{- with .Values.deploymentStrategy }} + strategy: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + template: + metadata: + labels: + {{- include "grafana.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + checksum/config: {{ include "grafana.configData" . | sha256sum }} + {{- if .Values.dashboards }} + checksum/dashboards-json-config: {{ include (print $.Template.BasePath "/dashboards-json-configmap.yaml") . | sha256sum }} + {{- end }} + checksum/sc-dashboard-provider-config: {{ include "grafana.configDashboardProviderData" . | sha256sum }} + {{- if and (or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret))) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + checksum/secret: {{ include "grafana.secretsData" . | sha256sum }} + {{- end }} + {{- if .Values.envRenderSecret }} + checksum/secret-env: {{ tpl (toYaml .Values.envRenderSecret) . | sha256sum }} + {{- end }} + kubectl.kubernetes.io/default-container: {{ .Chart.Name }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include "grafana.pod" . | nindent 6 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/extra-manifests.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/extra-manifests.yaml new file mode 100644 index 0000000000..a9bb3b6ba8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/extra-manifests.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraObjects }} +--- +{{ tpl (toYaml .) $ }} +{{ end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/headless-service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/headless-service.yaml new file mode 100644 index 0000000000..3028589d32 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/headless-service.yaml @@ -0,0 +1,22 @@ +{{- $sts := list "sts" "StatefulSet" "statefulset" -}} +{{- if or .Values.headlessService (and .Values.persistence.enabled (not .Values.persistence.existingClaim) (has .Values.persistence.type $sts)) }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "grafana.fullname" . }}-headless + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + clusterIP: None + selector: + {{- include "grafana.selectorLabels" . | nindent 4 }} + type: ClusterIP + ports: + - name: {{ .Values.gossipPortName }}-tcp + port: 9094 +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/hpa.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/hpa.yaml new file mode 100644 index 0000000000..46bbcb49a2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/hpa.yaml @@ -0,0 +1,52 @@ +{{- $sts := list "sts" "StatefulSet" "statefulset" -}} +{{- if .Values.autoscaling.enabled }} +apiVersion: {{ include "grafana.hpa.apiVersion" . }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "grafana.name" . }} + helm.sh/chart: {{ include "grafana.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + {{- if has .Values.persistence.type $sts }} + kind: StatefulSet + {{- else }} + kind: Deployment + {{- end }} + name: {{ include "grafana.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetMemory }} + - type: Resource + resource: + name: memory + {{- if eq (include "grafana.hpa.apiVersion" .) "autoscaling/v2beta1" }} + targetAverageUtilization: {{ .Values.autoscaling.targetMemory }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemory }} + {{- end }} + {{- end }} + {{- if .Values.autoscaling.targetCPU }} + - type: Resource + resource: + name: cpu + {{- if eq (include "grafana.hpa.apiVersion" .) "autoscaling/v2beta1" }} + targetAverageUtilization: {{ .Values.autoscaling.targetCPU }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPU }} + {{- end }} + {{- end }} + {{- if .Values.autoscaling.behavior }} + behavior: {{ toYaml .Values.autoscaling.behavior | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-deployment.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-deployment.yaml new file mode 100644 index 0000000000..a6b055c82b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-deployment.yaml @@ -0,0 +1,199 @@ +{{ if .Values.imageRenderer.enabled }} +{{- $root := . -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "grafana.fullname" . }}-image-renderer + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.imageRenderer.labels" . | nindent 4 }} + {{- with .Values.imageRenderer.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.imageRenderer.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and (not .Values.imageRenderer.autoscaling.enabled) (.Values.imageRenderer.replicas) }} + replicas: {{ .Values.imageRenderer.replicas }} + {{- end }} + revisionHistoryLimit: {{ .Values.imageRenderer.revisionHistoryLimit }} + selector: + matchLabels: + {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }} + + {{- with .Values.imageRenderer.deploymentStrategy }} + strategy: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + template: + metadata: + labels: + {{- include "grafana.imageRenderer.selectorLabels" . | nindent 8 }} + {{- with .Values.imageRenderer.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.imageRenderer.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imageRenderer.schedulerName }} + schedulerName: "{{ . }}" + {{- end }} + {{- with .Values.imageRenderer.serviceAccountName }} + serviceAccountName: "{{ . }}" + {{- end }} + {{- with .Values.imageRenderer.securityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.imageRenderer.hostAliases }} + hostAliases: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.imageRenderer.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.imageRenderer.image.pullSecrets }} + imagePullSecrets: + {{- range . }} + - name: {{ tpl . $root }} + {{- end}} + {{- end }} + containers: + - name: {{ .Chart.Name }}-image-renderer + {{- $registry := include "system_default_registry" . | default .Values.imageRenderer.image.registry -}} + {{- if .Values.imageRenderer.image.sha }} + image: "{{ $registry }}{{ .Values.imageRenderer.image.repository }}:{{ .Values.imageRenderer.image.tag }}@sha256:{{ .Values.imageRenderer.image.sha }}" + {{- else }} + image: "{{ $registry }}{{ .Values.imageRenderer.image.repository }}:{{ .Values.imageRenderer.image.tag }}" + {{- end }} + imagePullPolicy: {{ .Values.imageRenderer.image.pullPolicy }} + {{- if .Values.imageRenderer.command }} + command: + {{- range .Values.imageRenderer.command }} + - {{ . }} + {{- end }} + {{- end}} + ports: + - name: {{ .Values.imageRenderer.service.portName }} + containerPort: {{ .Values.imageRenderer.service.targetPort }} + protocol: TCP + livenessProbe: + httpGet: + path: / + port: {{ .Values.imageRenderer.service.portName }} + env: + - name: HTTP_PORT + value: {{ .Values.imageRenderer.service.targetPort | quote }} + {{- if .Values.imageRenderer.serviceMonitor.enabled }} + - name: ENABLE_METRICS + value: "true" + {{- end }} + {{- range $key, $value := .Values.imageRenderer.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 16 }} + {{- end }} + {{- range $key, $value := .Values.imageRenderer.env }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + {{- with .Values.imageRenderer.containerSecurityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /tmp + name: image-renderer-tmpfs + {{- range .Values.imageRenderer.extraConfigmapMounts }} + - name: {{ tpl .name $root }} + mountPath: {{ tpl .mountPath $root }} + subPath: {{ tpl (.subPath | default "") $root }} + readOnly: {{ .readOnly }} + {{- end }} + {{- range .Values.imageRenderer.extraSecretMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + readOnly: {{ .readOnly }} + subPath: {{ .subPath | default "" }} + {{- end }} + {{- range .Values.imageRenderer.extraVolumeMounts }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + subPath: {{ .subPath | default "" }} + readOnly: {{ .readOnly }} + {{- end }} + {{- with .Values.imageRenderer.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.imageRenderer.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.imageRenderer.affinity }} + affinity: + {{- tpl (toYaml .) $root | nindent 8 }} + {{- end }} + {{- with .Values.imageRenderer.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: image-renderer-tmpfs + emptyDir: {} + {{- range .Values.imageRenderer.extraConfigmapMounts }} + - name: {{ tpl .name $root }} + configMap: + name: {{ tpl .configMap $root }} + {{- with .items }} + items: + {{- toYaml . | nindent 14 }} + {{- end }} + {{- end }} + {{- range .Values.imageRenderer.extraSecretMounts }} + {{- if .secretName }} + - name: {{ .name }} + secret: + secretName: {{ .secretName }} + defaultMode: {{ .defaultMode }} + {{- with .items }} + items: + {{- toYaml . | nindent 14 }} + {{- end }} + {{- else if .projected }} + - name: {{ .name }} + projected: + {{- toYaml .projected | nindent 12 }} + {{- else if .csi }} + - name: {{ .name }} + csi: + {{- toYaml .csi | nindent 12 }} + {{- end }} + {{- end }} + {{- range .Values.imageRenderer.extraVolumes }} + - name: {{ .name }} + {{- if .existingClaim }} + persistentVolumeClaim: + claimName: {{ .existingClaim }} + {{- else if .hostPath }} + hostPath: + {{ toYaml .hostPath | nindent 12 }} + {{- else if .csi }} + csi: + {{- toYaml .csi | nindent 12 }} + {{- else if .configMap }} + configMap: + {{- toYaml .configMap | nindent 12 }} + {{- else if .emptyDir }} + emptyDir: + {{- toYaml .emptyDir | nindent 12 }} + {{- else }} + emptyDir: {} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-hpa.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-hpa.yaml new file mode 100644 index 0000000000..b0f0059b79 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-hpa.yaml @@ -0,0 +1,47 @@ +{{- if and .Values.imageRenderer.enabled .Values.imageRenderer.autoscaling.enabled }} +apiVersion: {{ include "grafana.hpa.apiVersion" . }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "grafana.fullname" . }}-image-renderer + namespace: {{ include "grafana.namespace" . }} + labels: + app.kubernetes.io/name: {{ include "grafana.name" . }}-image-renderer + helm.sh/chart: {{ include "grafana.chart" . }} + app.kubernetes.io/managed-by: {{ .Release.Service }} + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "grafana.fullname" . }}-image-renderer + minReplicas: {{ .Values.imageRenderer.autoscaling.minReplicas }} + maxReplicas: {{ .Values.imageRenderer.autoscaling.maxReplicas }} + metrics: + {{- if .Values.imageRenderer.autoscaling.targetMemory }} + - type: Resource + resource: + name: memory + {{- if eq (include "grafana.hpa.apiVersion" .) "autoscaling/v2beta1" }} + targetAverageUtilization: {{ .Values.imageRenderer.autoscaling.targetMemory }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.imageRenderer.autoscaling.targetMemory }} + {{- end }} + {{- end }} + {{- if .Values.imageRenderer.autoscaling.targetCPU }} + - type: Resource + resource: + name: cpu + {{- if eq (include "grafana.hpa.apiVersion" .) "autoscaling/v2beta1" }} + targetAverageUtilization: {{ .Values.imageRenderer.autoscaling.targetCPU }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.imageRenderer.autoscaling.targetCPU }} + {{- end }} + {{- end }} + {{- if .Values.imageRenderer.autoscaling.behavior }} + behavior: {{ toYaml .Values.imageRenderer.autoscaling.behavior | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-network-policy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-network-policy.yaml new file mode 100644 index 0000000000..bcbd24976c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-network-policy.yaml @@ -0,0 +1,79 @@ +{{- if and .Values.imageRenderer.enabled .Values.imageRenderer.networkPolicy.limitIngress }} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "grafana.fullname" . }}-image-renderer-ingress + namespace: {{ include "grafana.namespace" . }} + annotations: + comment: Limit image-renderer ingress traffic from grafana +spec: + podSelector: + matchLabels: + {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }} + {{- with .Values.imageRenderer.podLabels }} + {{- toYaml . | nindent 6 }} + {{- end }} + + policyTypes: + - Ingress + ingress: + - ports: + - port: {{ .Values.imageRenderer.service.targetPort }} + protocol: TCP + from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ include "grafana.namespace" . }} + podSelector: + matchLabels: + {{- include "grafana.selectorLabels" . | nindent 14 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 14 }} + {{- end }} + {{- with .Values.imageRenderer.networkPolicy.extraIngressSelectors -}} + {{ toYaml . | nindent 8 }} + {{- end }} +{{- end }} + +{{- if and .Values.imageRenderer.enabled .Values.imageRenderer.networkPolicy.limitEgress }} +--- +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "grafana.fullname" . }}-image-renderer-egress + namespace: {{ include "grafana.namespace" . }} + annotations: + comment: Limit image-renderer egress traffic to grafana +spec: + podSelector: + matchLabels: + {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }} + {{- with .Values.imageRenderer.podLabels }} + {{- toYaml . | nindent 6 }} + {{- end }} + + policyTypes: + - Egress + egress: + # allow dns resolution + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + # talk only to grafana + - ports: + - port: {{ .Values.service.targetPort }} + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ include "grafana.namespace" . }} + podSelector: + matchLabels: + {{- include "grafana.selectorLabels" . | nindent 14 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 14 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-service.yaml new file mode 100644 index 0000000000..f8da127cf8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-service.yaml @@ -0,0 +1,31 @@ +{{- if and .Values.imageRenderer.enabled .Values.imageRenderer.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "grafana.fullname" . }}-image-renderer + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.imageRenderer.labels" . | nindent 4 }} + {{- with .Values.imageRenderer.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.imageRenderer.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: ClusterIP + {{- with .Values.imageRenderer.service.clusterIP }} + clusterIP: {{ . }} + {{- end }} + ports: + - name: {{ .Values.imageRenderer.service.portName }} + port: {{ .Values.imageRenderer.service.port }} + protocol: TCP + targetPort: {{ .Values.imageRenderer.service.targetPort }} + {{- with .Values.imageRenderer.appProtocol }} + appProtocol: {{ . }} + {{- end }} + selector: + {{- include "grafana.imageRenderer.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-servicemonitor.yaml new file mode 100644 index 0000000000..5d9f09d266 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/image-renderer-servicemonitor.yaml @@ -0,0 +1,48 @@ +{{- if .Values.imageRenderer.serviceMonitor.enabled }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "grafana.fullname" . }}-image-renderer + {{- if .Values.imageRenderer.serviceMonitor.namespace }} + namespace: {{ tpl .Values.imageRenderer.serviceMonitor.namespace . }} + {{- else }} + namespace: {{ include "grafana.namespace" . }} + {{- end }} + labels: + {{- include "grafana.imageRenderer.labels" . | nindent 4 }} + {{- with .Values.imageRenderer.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + endpoints: + - port: {{ .Values.imageRenderer.service.portName }} + {{- with .Values.imageRenderer.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.imageRenderer.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + honorLabels: true + path: {{ .Values.imageRenderer.serviceMonitor.path }} + scheme: {{ .Values.imageRenderer.serviceMonitor.scheme }} + {{- with .Values.imageRenderer.serviceMonitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.imageRenderer.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + jobLabel: "{{ .Release.Name }}-image-renderer" + selector: + matchLabels: + {{- include "grafana.imageRenderer.selectorLabels" . | nindent 6 }} + namespaceSelector: + matchNames: + - {{ include "grafana.namespace" . }} + {{- with .Values.imageRenderer.serviceMonitor.targetLabels }} + targetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/ingress.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/ingress.yaml new file mode 100644 index 0000000000..b2ffd81095 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/ingress.yaml @@ -0,0 +1,78 @@ +{{- if .Values.ingress.enabled -}} +{{- $ingressApiIsStable := eq (include "grafana.ingress.isStable" .) "true" -}} +{{- $ingressSupportsIngressClassName := eq (include "grafana.ingress.supportsIngressClassName" .) "true" -}} +{{- $ingressSupportsPathType := eq (include "grafana.ingress.supportsPathType" .) "true" -}} +{{- $fullName := include "grafana.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +{{- $ingressPath := .Values.ingress.path -}} +{{- $ingressPathType := .Values.ingress.pathType -}} +{{- $extraPaths := .Values.ingress.extraPaths -}} +apiVersion: {{ include "grafana.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.ingress.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ tpl $value $ | quote }} + {{- end }} + {{- end }} +spec: + {{- if and $ingressSupportsIngressClassName .Values.ingress.ingressClassName }} + ingressClassName: {{ .Values.ingress.ingressClassName }} + {{- end -}} + {{- with .Values.ingress.tls }} + tls: + {{- tpl (toYaml .) $ | nindent 4 }} + {{- end }} + rules: + {{- if .Values.ingress.hosts }} + {{- range .Values.ingress.hosts }} + - host: {{ tpl . $ | quote }} + http: + paths: + {{- with $extraPaths }} + {{- toYaml . | nindent 10 }} + {{- end }} + - path: {{ $ingressPath }} + {{- if $ingressSupportsPathType }} + pathType: {{ $ingressPathType }} + {{- end }} + backend: + {{- if $ingressApiIsStable }} + service: + name: {{ $fullName }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end }} + {{- else }} + - http: + paths: + - backend: + {{- if $ingressApiIsStable }} + service: + name: {{ $fullName }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- with $ingressPath }} + path: {{ . }} + {{- end }} + {{- if $ingressSupportsPathType }} + pathType: {{ $ingressPathType }} + {{- end }} + {{- end -}} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/networkpolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/networkpolicy.yaml new file mode 100644 index 0000000000..4cd3ed6976 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/networkpolicy.yaml @@ -0,0 +1,61 @@ +{{- if .Values.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + policyTypes: + {{- if .Values.networkPolicy.ingress }} + - Ingress + {{- end }} + {{- if .Values.networkPolicy.egress.enabled }} + - Egress + {{- end }} + podSelector: + matchLabels: + {{- include "grafana.selectorLabels" . | nindent 6 }} + + {{- if .Values.networkPolicy.egress.enabled }} + egress: + {{- if not .Values.networkPolicy.egress.blockDNSResolution }} + - ports: + - port: 53 + protocol: UDP + {{- end }} + - ports: + {{ .Values.networkPolicy.egress.ports | toJson }} + {{- with .Values.networkPolicy.egress.to }} + to: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.networkPolicy.ingress }} + ingress: + - ports: + - port: {{ .Values.service.targetPort }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ include "grafana.fullname" . }}-client: "true" + {{- with .Values.networkPolicy.explicitNamespacesSelector }} + - namespaceSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + - podSelector: + matchLabels: + {{- include "grafana.labels" . | nindent 14 }} + role: read + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/nginx-config.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/nginx-config.yaml new file mode 100644 index 0000000000..557471f6ff --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/nginx-config.yaml @@ -0,0 +1,94 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-nginx-proxy-config + namespace: {{ template "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} +data: + nginx.conf: |- + worker_processes auto; + error_log /dev/stdout warn; + pid /var/cache/nginx/nginx.pid; + + events { + worker_connections 1024; + } + + http { + include /etc/nginx/mime.types; + log_format main '[$time_local - $status] $remote_addr - $remote_user $request ($http_referer)'; + + proxy_connect_timeout 10; + proxy_read_timeout 180; + proxy_send_timeout 5; + proxy_buffering off; + proxy_cache_path /var/cache/nginx/cache levels=1:2 keys_zone=my_zone:100m inactive=1d max_size=10g; + + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + server { + listen 8080; + access_log off; + + gzip on; + gzip_min_length 1k; + gzip_comp_level 2; + gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript image/jpeg image/gif image/png; + gzip_vary on; + gzip_disable "MSIE [1-6]\."; + + proxy_set_header Host $host; + + location /api/dashboards { + proxy_pass http://localhost:3000; + } + + location /api/search { + proxy_pass http://localhost:3000; + + sub_filter_types application/json; + sub_filter_once off; + } + + location /api/live/ { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $http_host; + proxy_pass http://localhost:3000; + } + + location / { + proxy_cache my_zone; + proxy_cache_valid 200 302 1d; + proxy_cache_valid 301 30d; + proxy_cache_valid any 5m; + proxy_cache_bypass $http_cache_control; + add_header X-Proxy-Cache $upstream_cache_status; + add_header Cache-Control "public"; + + proxy_pass http://localhost:3000/; + + sub_filter_once off; + + {{- if eq .Values.global.cattle.clusterId "local" -}} + sub_filter '"appSubUrl":""' '"appSubUrl":"/api/v1/namespaces/{{ template "grafana.namespace" . }}/services/http:{{ template "grafana.fullname" . }}:{{ .Values.service.port }}/proxy"'; + {{- else -}} + sub_filter '"appSubUrl":""' '"appSubUrl":"/k8s/clusters/{{ .Values.global.cattle.clusterId }}/api/v1/namespaces/{{ template "grafana.namespace" . }}/services/http:{{ template "grafana.fullname" . }}:{{ .Values.service.port }}/proxy"'; + {{- end -}} + + sub_filter ':"/avatar/' ':"avatar/'; + + if ($request_filename ~ .*\.(?:js|css|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$) { + expires 90d; + } + + rewrite ^/k8s/clusters/.*/proxy(.*) /$1 break; + + } + } + } diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/poddisruptionbudget.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000000..05251214ac --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if .Values.podDisruptionBudget }} +apiVersion: {{ include "grafana.podDisruptionBudget.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ . }} + {{- end }} + {{- with .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ . }} + {{- end }} + selector: + matchLabels: + {{- include "grafana.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/podsecuritypolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/podsecuritypolicy.yaml new file mode 100644 index 0000000000..ebbdef5b5e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/podsecuritypolicy.yaml @@ -0,0 +1,45 @@ +{{- if and .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ include "grafana.fullname" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} +{{- if .Values.rbac.pspAnnotations }} + annotations: {{ toYaml .Values.rbac.pspAnnotations | nindent 4 }} +{{- end }} +spec: + privileged: false + allowPrivilegeEscalation: false + requiredDropCapabilities: + # Default set from Docker, with DAC_OVERRIDE and CHOWN + - ALL + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'csi' + - 'secret' + - 'downwardAPI' + - 'persistentVolumeClaim' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + 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/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/pvc.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/pvc.yaml new file mode 100644 index 0000000000..b5fd5d4a3b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/pvc.yaml @@ -0,0 +1,41 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) (eq .Values.persistence.type "pvc")}} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.persistence.extraPvcLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.persistence.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.persistence.finalizers }} + finalizers: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + accessModes: +{{- $_ := required "Must provide at least one access mode for persistent volumes used by Grafana" .Values.persistence.accessModes }} +{{- $_ := required "Must provide at least one access mode for persistent volumes used by Grafana" (first .Values.persistence.accessModes) }} + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- if and (.Values.persistence.lookupVolumeName) (lookup "v1" "PersistentVolumeClaim" (include "grafana.namespace" .) (include "grafana.fullname" .)) }} + volumeName: {{ (lookup "v1" "PersistentVolumeClaim" (include "grafana.namespace" .) (include "grafana.fullname" .)).spec.volumeName }} + {{- end }} + {{- with .Values.persistence.storageClassName }} + storageClassName: {{ . }} + {{- end }} + {{- with .Values.persistence.selectorLabels }} + selector: + matchLabels: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/role.yaml new file mode 100644 index 0000000000..4b5edd978c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/role.yaml @@ -0,0 +1,32 @@ +{{- if and .Values.rbac.create (not .Values.rbac.useExistingRole) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- if or .Values.rbac.pspEnabled (and .Values.rbac.namespaced (or .Values.sidecar.dashboards.enabled .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled .Values.rbac.extraRoleRules)) }} +rules: + {{- if and .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} + - apiGroups: ['extensions'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: [{{ include "grafana.fullname" . }}] + {{- end }} + {{- if and .Values.rbac.namespaced (or .Values.sidecar.dashboards.enabled .Values.sidecar.datasources.enabled .Values.sidecar.plugins.enabled) }} + - apiGroups: [""] # "" indicates the core API group + resources: ["configmaps", "secrets"] + verbs: ["get", "watch", "list"] + {{- end }} + {{- with .Values.rbac.extraRoleRules }} + {{- toYaml . | nindent 2 }} + {{- end}} +{{- else }} +rules: [] +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/rolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/rolebinding.yaml new file mode 100644 index 0000000000..58f77c6b0b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/rolebinding.yaml @@ -0,0 +1,25 @@ +{{- if .Values.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + {{- if .Values.rbac.useExistingRole }} + name: {{ .Values.rbac.useExistingRole }} + {{- else }} + name: {{ include "grafana.fullname" . }} + {{- end }} +subjects: +- kind: ServiceAccount + name: {{ include "grafana.serviceAccountName" . }} + namespace: {{ include "grafana.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/secret-env.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/secret-env.yaml new file mode 100644 index 0000000000..eb14aac707 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/secret-env.yaml @@ -0,0 +1,14 @@ +{{- if .Values.envRenderSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "grafana.fullname" . }}-env + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} +type: Opaque +data: +{{- range $key, $val := .Values.envRenderSecret }} + {{ $key }}: {{ tpl ($val | toString) $ | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/secret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/secret.yaml new file mode 100644 index 0000000000..fd2ca50f4b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/secret.yaml @@ -0,0 +1,16 @@ +{{- if or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret)) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +type: Opaque +data: + {{- include "grafana.secretsData" . | nindent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/service.yaml new file mode 100644 index 0000000000..022328c114 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/service.yaml @@ -0,0 +1,67 @@ +{{- if .Values.service.enabled }} +{{- $root := . }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.service.annotations }} + annotations: + {{- tpl (toYaml . | nindent 4) $root }} + {{- end }} +spec: + {{- if (or (eq .Values.service.type "ClusterIP") (empty .Values.service.type)) }} + type: ClusterIP + {{- with .Values.service.clusterIP }} + clusterIP: {{ . }} + {{- end }} + {{- else if eq .Values.service.type "LoadBalancer" }} + type: LoadBalancer + {{- with .Values.service.loadBalancerIP }} + loadBalancerIP: {{ . }} + {{- end }} + {{- with .Values.service.loadBalancerClass }} + loadBalancerClass: {{ . }} + {{- end }} + {{- with .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- else }} + type: {{ .Values.service.type }} + {{- end }} + {{- if .Values.service.ipFamilyPolicy }} + ipFamilyPolicy: {{ .Values.service.ipFamilyPolicy }} + {{- end }} + {{- if .Values.service.ipFamilies }} + ipFamilies: {{ .Values.service.ipFamilies | toYaml | nindent 2 }} + {{- end }} + {{- with .Values.service.externalIPs }} + externalIPs: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ . }} + {{- end }} + ports: + - name: {{ .Values.service.portName }} + port: {{ .Values.service.port }} + protocol: TCP + targetPort: {{ .Values.service.targetPort }} + {{- with .Values.service.appProtocol }} + appProtocol: {{ . }} + {{- end }} + {{- if (and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort))) }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + {{- with .Values.extraExposePorts }} + {{- tpl (toYaml . | nindent 4) $root }} + {{- end }} + selector: + {{- include "grafana.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/serviceaccount.yaml new file mode 100644 index 0000000000..ffca0717ae --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +automountServiceAccountToken: {{ .Values.serviceAccount.autoMount | default .Values.serviceAccount.automountServiceAccountToken }} +metadata: + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- tpl (toYaml . | nindent 4) $ }} + {{- end }} + name: {{ include "grafana.serviceAccountName" . }} + namespace: {{ include "grafana.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/servicemonitor.yaml new file mode 100644 index 0000000000..160a9c5562 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/servicemonitor.yaml @@ -0,0 +1,66 @@ +{{- if .Values.serviceMonitor.enabled }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "grafana.fullname" . }} + {{- if .Values.serviceMonitor.namespace }} + namespace: {{ tpl .Values.serviceMonitor.namespace . }} + {{- else }} + namespace: {{ include "grafana.namespace" . }} + {{- end }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.serviceMonitor.labels }} + {{- tpl (toYaml . | nindent 4) $ }} + {{- end }} +spec: + endpoints: + - port: {{ .Values.service.portName }} + {{- with .Values.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + honorLabels: true + path: {{ .Values.serviceMonitor.path }} + scheme: {{ .Values.serviceMonitor.scheme }} + {{- with .Values.serviceMonitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 6 }} + {{- end }} + metricRelabelings: + {{- if .Values.serviceMonitor.metricRelabelings }} + {{- toYaml .Values.serviceMonitor.metricRelabelings | nindent 6 }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName }} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} + {{- with .Values.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + jobLabel: "{{ .Release.Name }}" + selector: + matchLabels: + {{- include "grafana.selectorLabels" . | nindent 6 }} + namespaceSelector: + matchNames: + - {{ include "grafana.namespace" . }} + {{- with .Values.serviceMonitor.targetLabels }} + targetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/statefulset.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/statefulset.yaml new file mode 100644 index 0000000000..49278083e8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/statefulset.yaml @@ -0,0 +1,58 @@ +{{- $sts := list "sts" "StatefulSet" "statefulset" -}} +{{- if (or (.Values.useStatefulSet) (and .Values.persistence.enabled (not .Values.persistence.existingClaim) (has .Values.persistence.type $sts)))}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "grafana.fullname" . }} + namespace: {{ include "grafana.namespace" . }} + labels: + {{- include "grafana.labels" . | nindent 4 }} + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicas }} + selector: + matchLabels: + {{- include "grafana.selectorLabels" . | nindent 6 }} + serviceName: {{ include "grafana.fullname" . }}-headless + template: + metadata: + labels: + {{- include "grafana.selectorLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/dashboards-json-config: {{ include (print $.Template.BasePath "/dashboards-json-configmap.yaml") . | sha256sum }} + checksum/sc-dashboard-provider-config: {{ include (print $.Template.BasePath "/configmap-dashboard-provider.yaml") . | sha256sum }} + {{- if and (or (and (not .Values.admin.existingSecret) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD__FILE) (not .Values.env.GF_SECURITY_ADMIN_PASSWORD)) (and .Values.ldap.enabled (not .Values.ldap.existingSecret))) (not .Values.env.GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION) }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- end }} + kubectl.kubernetes.io/default-container: {{ .Chart.Name }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- include "grafana.pod" . | nindent 6 }} + {{- if .Values.persistence.enabled}} + volumeClaimTemplates: + - metadata: + name: storage + spec: +{{- $_ := required "Must provide at least one access mode for persistent volumes used by Grafana" .Values.persistence.accessModes }} +{{- $_ := required "Must provide at least one access mode for persistent volumes used by Grafana" (first .Values.persistence.accessModes) }} + accessModes: {{ .Values.persistence.accessModes }} + storageClassName: {{ .Values.persistence.storageClassName }} + resources: + requests: + storage: {{ required "Must provide size for persistent volumes used by Grafana" .Values.persistence.size }} + {{- with .Values.persistence.selectorLabels }} + selector: + matchLabels: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-configmap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-configmap.yaml new file mode 100644 index 0000000000..01c96c9243 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-configmap.yaml @@ -0,0 +1,20 @@ +{{- if .Values.testFramework.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "grafana.fullname" . }}-test + namespace: {{ include "grafana.namespace" . }} + annotations: + "helm.sh/hook": test-success + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" + labels: + {{- include "grafana.labels" . | nindent 4 }} +data: + run.sh: |- + @test "Test Health" { + url="http://{{ include "grafana.fullname" . }}/api/health" + + code=$(wget --server-response --spider --timeout 90 --tries 10 ${url} 2>&1 | awk '/^ HTTP/{print $2}') + [ "$code" == "200" ] + } +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-podsecuritypolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-podsecuritypolicy.yaml new file mode 100644 index 0000000000..1821772a45 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-podsecuritypolicy.yaml @@ -0,0 +1,32 @@ +{{- if and (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") .Values.testFramework.enabled .Values.rbac.pspEnabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ include "grafana.fullname" . }}-test + annotations: + "helm.sh/hook": test-success + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" + labels: + {{- include "grafana.labels" . | nindent 4 }} +spec: + allowPrivilegeEscalation: true + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + fsGroup: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + runAsUser: + rule: RunAsAny + volumes: + - configMap + - downwardAPI + - emptyDir + - projected + - csi + - secret +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-role.yaml new file mode 100644 index 0000000000..cb4c782040 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-role.yaml @@ -0,0 +1,17 @@ +{{- if and (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") .Values.testFramework.enabled .Values.rbac.pspEnabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "grafana.fullname" . }}-test + namespace: {{ include "grafana.namespace" . }} + annotations: + "helm.sh/hook": test-success + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" + labels: + {{- include "grafana.labels" . | nindent 4 }} +rules: + - apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: [{{ include "grafana.fullname" . }}-test] +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-rolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-rolebinding.yaml new file mode 100644 index 0000000000..f40d791f6c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-rolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") .Values.testFramework.enabled .Values.rbac.pspEnabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "grafana.fullname" . }}-test + namespace: {{ include "grafana.namespace" . }} + annotations: + "helm.sh/hook": test-success + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" + labels: + {{- include "grafana.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "grafana.fullname" . }}-test +subjects: + - kind: ServiceAccount + name: {{ include "grafana.serviceAccountNameTest" . }} + namespace: {{ include "grafana.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-serviceaccount.yaml new file mode 100644 index 0000000000..38fba3596a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test-serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if and .Values.testFramework.enabled .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "grafana.labels" . | nindent 4 }} + name: {{ include "grafana.serviceAccountNameTest" . }} + namespace: {{ include "grafana.namespace" . }} + annotations: + "helm.sh/hook": test-success + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test.yaml new file mode 100644 index 0000000000..83aaa185c2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/templates/tests/test.yaml @@ -0,0 +1,53 @@ +{{- if .Values.testFramework.enabled }} +{{- $root := . }} +apiVersion: v1 +kind: Pod +metadata: + name: {{ include "grafana.fullname" . }}-test + labels: + {{- include "grafana.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success + "helm.sh/hook-delete-policy": "before-hook-creation,hook-succeeded" + namespace: {{ include "grafana.namespace" . }} +spec: + serviceAccountName: {{ include "grafana.serviceAccountNameTest" . }} + {{- with .Values.testFramework.securityContext }} + securityContext: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.image.pullSecrets .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- include "grafana.imagePullSecrets" (dict "root" $root "imagePullSecrets" .Values.image.pullSecrets) | nindent 4 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- tpl (toYaml .) $root | nindent 4 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 4 }} + {{- end }} + containers: + - name: {{ .Release.Name }}-test + image: "{{ template "system_default_registry" . | default .Values.testFramework.image.registry }}/{{ .Values.testFramework.image.repository }}:{{ .Values.testFramework.image.tag }}" + imagePullPolicy: "{{ .Values.testFramework.imagePullPolicy}}" + command: ["/opt/bats/bin/bats", "-t", "/tests/run.sh"] + volumeMounts: + - mountPath: /tests + name: tests + readOnly: true + {{- with .Values.testFramework.resources }} + resources: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: tests + configMap: + name: {{ include "grafana.fullname" . }}-test + restartPolicy: Never +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/values.yaml new file mode 100644 index 0000000000..c338ae041e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/grafana/values.yaml @@ -0,0 +1,1365 @@ +global: + cattle: + systemDefaultRegistry: "" + + # To help compatibility with other charts which use global.imagePullSecrets. + # Allow either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style). + # Can be templated. + # global: + # imagePullSecrets: + # - name: pullSecret1 + # - name: pullSecret2 + # or + # global: + # imagePullSecrets: + # - pullSecret1 + # - pullSecret2 + imagePullSecrets: [] + +rbac: + create: true + ## Use an existing ClusterRole/Role (depending on rbac.namespaced false/true) + # useExistingRole: name-of-some-role + # useExistingClusterRole: name-of-some-clusterRole + pspEnabled: false + pspUseAppArmor: false + namespaced: false + extraRoleRules: [] + # - apiGroups: [] + # resources: [] + # verbs: [] + extraClusterRoleRules: [] + # - apiGroups: [] + # resources: [] + # verbs: [] +serviceAccount: + create: true + name: + nameTest: + ## ServiceAccount labels. + labels: {} + ## Service account annotations. Can be templated. + # annotations: + # eks.amazonaws.com/role-arn: arn:aws:iam::123456789000:role/iam-role-name-here + + ## autoMount is deprecated in favor of automountServiceAccountToken + # autoMount: false + automountServiceAccountToken: true + +replicas: 1 + +## Create a headless service for the deployment +headlessService: false + +## Should the service account be auto mounted on the pod +automountServiceAccountToken: true + +## Create HorizontalPodAutoscaler object for deployment type +# +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 5 + targetCPU: "60" + targetMemory: "" + behavior: {} + +## See `kubectl explain poddisruptionbudget.spec` for more +## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ +podDisruptionBudget: {} +# apiVersion: "" +# minAvailable: 1 +# maxUnavailable: 1 + +## See `kubectl explain deployment.spec.strategy` for more +## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy +deploymentStrategy: + type: RollingUpdate + +readinessProbe: + httpGet: + path: /api/health + port: 3000 + +livenessProbe: + httpGet: + path: /api/health + port: 3000 + initialDelaySeconds: 60 + timeoutSeconds: 30 + failureThreshold: 10 + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: "default-scheduler" + +image: + repository: rancher/mirrored-grafana-grafana + # Overrides the Grafana image tag whose default is the chart appVersion + tag: 11.1.0 + sha: "" + pullPolicy: IfNotPresent + + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## Can be templated. + ## + pullSecrets: [] + # - myRegistrKeySecretName + +testFramework: + enabled: false + imagePullPolicy: IfNotPresent + securityContext: + runAsNonRoot: true + runAsUser: 1000 + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# dns configuration for pod +dnsPolicy: ~ +dnsConfig: {} + # nameservers: + # - 8.8.8.8 + # options: + # - name: ndots + # value: "2" + # - name: edns0 + +securityContext: + runAsNonRoot: true + runAsUser: 472 + runAsGroup: 472 + fsGroup: 472 + +containerSecurityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + +# Enable creating the grafana configmap +createConfigmap: true + +# Extra configmaps to mount in grafana pods +# Values are templated. +extraConfigmapMounts: [] + # - name: certs-configmap + # mountPath: /etc/grafana/ssl/ + # subPath: certificates.crt # (optional) + # configMap: certs-configmap + # readOnly: true + + +extraEmptyDirMounts: [] + # - name: provisioning-notifiers + # mountPath: /etc/grafana/provisioning/notifiers + + +# Apply extra labels to common labels. +extraLabels: {} + +## Assign a PriorityClassName to pods if set +# priorityClassName: + +downloadDashboardsImage: + repository: rancher/mirrored-curlimages-curl + tag: 8.9.1 + sha: "" + pullPolicy: IfNotPresent + +downloadDashboards: + env: {} + envFromSecret: "" + resources: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + envValueFrom: {} + # ENV_NAME: + # configMapKeyRef: + # name: configmap-name + # key: value_key + +## Pod Annotations +# podAnnotations: {} + +## ConfigMap Annotations +# configMapAnnotations: {} + # argocd.argoproj.io/sync-options: Replace=true + +## Pod Labels +# podLabels: {} + +podPortName: grafana +gossipPortName: gossip +## Deployment annotations +# annotations: {} + +## Expose the grafana service to be accessed from outside the cluster (LoadBalancer service). +## or access it from within the cluster (ClusterIP service). Set the service type and the port to serve it. +## ref: http://kubernetes.io/docs/user-guide/services/ +## +service: + enabled: true + type: ClusterIP + # Set the ip family policy to configure dual-stack see [Configure dual-stack](https://kubernetes.io/docs/concepts/services-networking/dual-stack/#services) + ipFamilyPolicy: "" + # Sets the families that should be supported and the order in which they should be applied to ClusterIP as well. Can be IPv4 and/or IPv6. + ipFamilies: [] + loadBalancerIP: "" + loadBalancerClass: "" + loadBalancerSourceRanges: [] + port: 80 + targetPort: 3000 + # targetPort: 4181 To be used with a proxy extraContainer + ## Service annotations. Can be templated. + annotations: {} + labels: {} + portName: service + # Adds the appProtocol field to the service. This allows to work with istio protocol selection. Ex: "http" or "tcp" + appProtocol: "" + +serviceMonitor: + ## If true, a ServiceMonitor CR is created for a prometheus operator + ## https://github.com/coreos/prometheus-operator + ## + enabled: false + path: /metrics + # namespace: monitoring (defaults to use the namespace this chart is deployed to) + labels: {} + interval: 30s + scheme: http + tlsConfig: {} + scrapeTimeout: 30s + relabelings: [] + metricRelabelings: [] + targetLabels: [] + +extraExposePorts: [] + # - name: keycloak + # port: 8080 + # targetPort: 8080 + +# overrides pod.spec.hostAliases in the grafana deployment's pods +hostAliases: [] + # - ip: "1.2.3.4" + # hostnames: + # - "my.host.com" + +ingress: + enabled: false + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + # Values can be templated + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + labels: {} + path: / + + # pathType is only for k8s >= 1.1= + pathType: Prefix + + hosts: + - chart-example.local + ## Extra paths to prepend to every host configuration. This is useful when working with annotation based services. + extraPaths: [] + # - path: /* + # backend: + # serviceName: ssl-redirect + # servicePort: use-annotation + ## Or for k8s > 1.19 + # - path: /* + # pathType: Prefix + # backend: + # service: + # name: ssl-redirect + # port: + # name: use-annotation + + + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} +# limits: +# cpu: 100m +# memory: 128Mi +# requests: +# cpu: 100m +# memory: 128Mi + +## Node labels for pod assignment +## ref: https://kubernetes.io/docs/user-guide/node-selection/ +# +nodeSelector: {} + +## Tolerations for pod assignment +## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +## +tolerations: [] + +## Affinity for pod assignment (evaluated as template) +## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +## +affinity: {} + +## Topology Spread Constraints +## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ +## +topologySpreadConstraints: [] + +## Additional init containers (evaluated as template) +## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ +## +extraInitContainers: [] + +## Enable an Specify container in extraContainers. This is meant to allow adding an authentication proxy to a grafana pod +extraContainers: "" +# extraContainers: | +# - name: proxy +# image: quay.io/gambol99/keycloak-proxy:latest +# args: +# - -provider=github +# - -client-id= +# - -client-secret= +# - -github-org= +# - -email-domain=* +# - -cookie-secret= +# - -http-address=http://0.0.0.0:4181 +# - -upstream-url=http://127.0.0.1:3000 +# ports: +# - name: proxy-web +# containerPort: 4181 + +## Volumes that can be used in init containers that will not be mounted to deployment pods +extraContainerVolumes: [] +# - name: volume-from-secret +# secret: +# secretName: secret-to-mount +# - name: empty-dir-volume +# emptyDir: {} + +## Enable persistence using Persistent Volume Claims +## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ +## +persistence: + type: pvc + enabled: false + # storageClassName: default + accessModes: + - ReadWriteOnce + size: 10Gi + # annotations: {} + finalizers: + - kubernetes.io/pvc-protection + # selectorLabels: {} + ## Sub-directory of the PV to mount. Can be templated. + # subPath: "" + ## Name of an existing PVC. Can be templated. + # existingClaim: + ## Extra labels to apply to a PVC. + extraPvcLabels: {} + disableWarning: false + + ## If persistence is not enabled, this allows to mount the + ## local storage in-memory to improve performance + ## + inMemory: + enabled: false + ## The maximum usage on memory medium EmptyDir would be + ## the minimum value between the SizeLimit specified + ## here and the sum of memory limits of all containers in a pod + ## + # sizeLimit: 300Mi + + ## If 'lookupVolumeName' is set to true, Helm will attempt to retrieve + ## the current value of 'spec.volumeName' and incorporate it into the template. + lookupVolumeName: true + +initChownData: + ## If false, data ownership will not be reset at startup + ## This allows the grafana-server to be run with an arbitrary user + ## + enabled: true + + ## initChownData container image + ## + image: + repository: rancher/mirrored-library-busybox + tag: "1.31.1" + sha: "" + pullPolicy: IfNotPresent + + ## initChownData resource requests and limits + ## Ref: http://kubernetes.io/docs/user-guide/compute-resources/ + ## + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + securityContext: + runAsNonRoot: false + runAsUser: 0 + seccompProfile: + type: RuntimeDefault + capabilities: + add: + - CHOWN + +# Administrator credentials when not using an existing secret (see below) +adminUser: admin +# adminPassword: strongpassword + +# Use an existing secret for the admin user. +admin: + ## Name of the secret. Can be templated. + existingSecret: "" + userKey: admin-user + passwordKey: admin-password + +## Define command to be executed at startup by grafana container +## Needed if using `vault-env` to manage secrets (ref: https://banzaicloud.com/blog/inject-secrets-into-pods-vault/) +## Default is "run.sh" as defined in grafana's Dockerfile +# command: +# - "sh" +# - "/run.sh" + +## Optionally define args if command is used +## Needed if using `hashicorp/envconsul` to manage secrets +## By default no arguments are set +# args: +# - "-secret" +# - "secret/grafana" +# - "./grafana" + +## Extra environment variables that will be pass onto deployment pods +## +## to provide grafana with access to CloudWatch on AWS EKS: +## 1. create an iam role of type "Web identity" with provider oidc.eks.* (note the provider for later) +## 2. edit the "Trust relationships" of the role, add a line inside the StringEquals clause using the +## same oidc eks provider as noted before (same as the existing line) +## also, replace NAMESPACE and prometheus-operator-grafana with the service account namespace and name +## +## "oidc.eks.us-east-1.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX:sub": "system:serviceaccount:NAMESPACE:prometheus-operator-grafana", +## +## 3. attach a policy to the role, you can use a built in policy called CloudWatchReadOnlyAccess +## 4. use the following env: (replace 123456789000 and iam-role-name-here with your aws account number and role name) +## +## env: +## AWS_ROLE_ARN: arn:aws:iam::123456789000:role/iam-role-name-here +## AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token +## AWS_REGION: us-east-1 +## +## 5. uncomment the EKS section in extraSecretMounts: below +## 6. uncomment the annotation section in the serviceAccount: above +## make sure to replace arn:aws:iam::123456789000:role/iam-role-name-here with your role arn + +env: {} + +## "valueFrom" environment variable references that will be added to deployment pods. Name is templated. +## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#envvarsource-v1-core +## Renders in container spec as: +## env: +## ... +## - name: +## valueFrom: +## +envValueFrom: {} + # ENV_NAME: + # configMapKeyRef: + # name: configmap-name + # key: value_key + +## The name of a secret in the same kubernetes namespace which contain values to be added to the environment +## This can be useful for auth tokens, etc. Value is templated. +envFromSecret: "" + +## Sensible environment variables that will be rendered as new secret object +## This can be useful for auth tokens, etc. +## If the secret values contains "{{", they'll need to be properly escaped so that they are not interpreted by Helm +## ref: https://helm.sh/docs/howto/charts_tips_and_tricks/#using-the-tpl-function +envRenderSecret: {} + +## The names of secrets in the same kubernetes namespace which contain values to be added to the environment +## Each entry should contain a name key, and can optionally specify whether the secret must be defined with an optional key. +## Name is templated. +envFromSecrets: [] +## - name: secret-name +## prefix: prefix +## optional: true + +## The names of conifgmaps in the same kubernetes namespace which contain values to be added to the environment +## Each entry should contain a name key, and can optionally specify whether the configmap must be defined with an optional key. +## Name is templated. +## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#configmapenvsource-v1-core +envFromConfigMaps: [] +## - name: configmap-name +## prefix: prefix +## optional: true + +# Inject Kubernetes services as environment variables. +# See https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/#environment-variables +enableServiceLinks: true + +## Additional grafana server secret mounts +# Defines additional mounts with secrets. Secrets must be manually created in the namespace. +extraSecretMounts: [] + # - name: secret-files + # mountPath: /etc/secrets + # secretName: grafana-secret-files + # readOnly: true + # subPath: "" + # + # for AWS EKS (cloudwatch) use the following (see also instruction in env: above) + # - name: aws-iam-token + # mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount + # readOnly: true + # projected: + # defaultMode: 420 + # sources: + # - serviceAccountToken: + # audience: sts.amazonaws.com + # expirationSeconds: 86400 + # path: token + # + # for CSI e.g. Azure Key Vault use the following + # - name: secrets-store-inline + # mountPath: /run/secrets + # readOnly: true + # csi: + # driver: secrets-store.csi.k8s.io + # readOnly: true + # volumeAttributes: + # secretProviderClass: "akv-grafana-spc" + # nodePublishSecretRef: # Only required when using service principal mode + # name: grafana-akv-creds # Only required when using service principal mode + +## Additional grafana server volume mounts +# Defines additional volume mounts. +extraVolumeMounts: [] + # - name: extra-volume-0 + # mountPath: /mnt/volume0 + # readOnly: true + # - name: extra-volume-1 + # mountPath: /mnt/volume1 + # readOnly: true + # - name: grafana-secrets + # mountPath: /mnt/volume2 + +## Additional Grafana server volumes +extraVolumes: [] + # - name: extra-volume-0 + # existingClaim: volume-claim + # - name: extra-volume-1 + # hostPath: + # path: /usr/shared/ + # type: "" + # - name: grafana-secrets + # csi: + # driver: secrets-store.csi.k8s.io + # readOnly: true + # volumeAttributes: + # secretProviderClass: "grafana-env-spc" + +## Container Lifecycle Hooks. Execute a specific bash command or make an HTTP request +lifecycleHooks: {} + # postStart: + # exec: + # command: [] + +## Pass the plugins you want installed as a list. +## +plugins: [] + # - digrich-bubblechart-panel + # - grafana-clock-panel + ## You can also use other plugin download URL, as long as they are valid zip files, + ## and specify the name of the plugin after the semicolon. Like this: + # - https://grafana.com/api/plugins/marcusolsson-json-datasource/versions/1.3.2/download;marcusolsson-json-datasource + +## Configure grafana datasources +## ref: http://docs.grafana.org/administration/provisioning/#datasources +## +datasources: {} +# datasources.yaml: +# apiVersion: 1 +# datasources: +# - name: Prometheus +# type: prometheus +# url: http://prometheus-prometheus-server +# access: proxy +# isDefault: true +# - name: CloudWatch +# type: cloudwatch +# access: proxy +# uid: cloudwatch +# editable: false +# jsonData: +# authType: default +# defaultRegion: us-east-1 +# deleteDatasources: [] +# - name: Prometheus + +## Configure grafana alerting (can be templated) +## ref: http://docs.grafana.org/administration/provisioning/#alerting +## +alerting: {} + # rules.yaml: + # apiVersion: 1 + # groups: + # - orgId: 1 + # name: '{{ .Chart.Name }}_my_rule_group' + # folder: my_first_folder + # interval: 60s + # rules: + # - uid: my_id_1 + # title: my_first_rule + # condition: A + # data: + # - refId: A + # datasourceUid: '-100' + # model: + # conditions: + # - evaluator: + # params: + # - 3 + # type: gt + # operator: + # type: and + # query: + # params: + # - A + # reducer: + # type: last + # type: query + # datasource: + # type: __expr__ + # uid: '-100' + # expression: 1==0 + # intervalMs: 1000 + # maxDataPoints: 43200 + # refId: A + # type: math + # dashboardUid: my_dashboard + # panelId: 123 + # noDataState: Alerting + # for: 60s + # annotations: + # some_key: some_value + # labels: + # team: sre_team_1 + # contactpoints.yaml: + # secret: + # apiVersion: 1 + # contactPoints: + # - orgId: 1 + # name: cp_1 + # receivers: + # - uid: first_uid + # type: pagerduty + # settings: + # integrationKey: XXX + # severity: critical + # class: ping failure + # component: Grafana + # group: app-stack + # summary: | + # {{ `{{ include "default.message" . }}` }} + +## Configure notifiers +## ref: http://docs.grafana.org/administration/provisioning/#alert-notification-channels +## +notifiers: {} +# notifiers.yaml: +# notifiers: +# - name: email-notifier +# type: email +# uid: email1 +# # either: +# org_id: 1 +# # or +# org_name: Main Org. +# is_default: true +# settings: +# addresses: an_email_address@example.com +# delete_notifiers: + +## Configure grafana dashboard providers +## ref: http://docs.grafana.org/administration/provisioning/#dashboards +## +## `path` must be /var/lib/grafana/dashboards/ +## +dashboardProviders: {} +# dashboardproviders.yaml: +# apiVersion: 1 +# providers: +# - name: 'default' +# orgId: 1 +# folder: '' +# type: file +# disableDeletion: false +# editable: true +# options: +# path: /var/lib/grafana/dashboards/default + +## Configure grafana dashboard to import +## NOTE: To use dashboards you must also enable/configure dashboardProviders +## ref: https://grafana.com/dashboards +## +## dashboards per provider, use provider name as key. +## +dashboards: {} + # default: + # some-dashboard: + # json: | + # $RAW_JSON + # custom-dashboard: + # file: dashboards/custom-dashboard.json + # prometheus-stats: + # gnetId: 2 + # revision: 2 + # datasource: Prometheus + # local-dashboard: + # url: https://example.com/repository/test.json + # token: '' + # local-dashboard-base64: + # url: https://example.com/repository/test-b64.json + # token: '' + # b64content: true + # local-dashboard-gitlab: + # url: https://example.com/repository/test-gitlab.json + # gitlabToken: '' + # local-dashboard-bitbucket: + # url: https://example.com/repository/test-bitbucket.json + # bearerToken: '' + # local-dashboard-azure: + # url: https://example.com/repository/test-azure.json + # basic: '' + # acceptHeader: '*/*' + +## Reference to external ConfigMap per provider. Use provider name as key and ConfigMap name as value. +## A provider dashboards must be defined either by external ConfigMaps or in values.yaml, not in both. +## ConfigMap data example: +## +## data: +## example-dashboard.json: | +## RAW_JSON +## +dashboardsConfigMaps: {} +# default: "" + +## Grafana's primary configuration +## NOTE: values in map will be converted to ini format +## ref: http://docs.grafana.org/installation/configuration/ +## +grafana.ini: + paths: + data: /var/lib/grafana/ + logs: /var/log/grafana + plugins: /var/lib/grafana/plugins + provisioning: /etc/grafana/provisioning + analytics: + check_for_updates: true + log: + mode: console + grafana_net: + url: https://grafana.net + server: + domain: "{{ if (and .Values.ingress.enabled .Values.ingress.hosts) }}{{ .Values.ingress.hosts | first }}{{ else }}''{{ end }}" +## grafana Authentication can be enabled with the following values on grafana.ini + # server: + # The full public facing url you use in browser, used for redirects and emails + # root_url: + # https://grafana.com/docs/grafana/latest/auth/github/#enable-github-in-grafana + # auth.github: + # enabled: false + # allow_sign_up: false + # scopes: user:email,read:org + # auth_url: https://github.com/login/oauth/authorize + # token_url: https://github.com/login/oauth/access_token + # api_url: https://api.github.com/user + # team_ids: + # allowed_organizations: + # client_id: + # client_secret: +## LDAP Authentication can be enabled with the following values on grafana.ini +## NOTE: Grafana will fail to start if the value for ldap.toml is invalid + # auth.ldap: + # enabled: true + # allow_sign_up: true + # config_file: /etc/grafana/ldap.toml + +## Grafana's LDAP configuration +## Templated by the template in _helpers.tpl +## NOTE: To enable the grafana.ini must be configured with auth.ldap.enabled +## ref: http://docs.grafana.org/installation/configuration/#auth-ldap +## ref: http://docs.grafana.org/installation/ldap/#configuration +ldap: + enabled: false + # `existingSecret` is a reference to an existing secret containing the ldap configuration + # for Grafana in a key `ldap-toml`. + existingSecret: "" + # `config` is the content of `ldap.toml` that will be stored in the created secret + config: "" + # config: |- + # verbose_logging = true + + # [[servers]] + # host = "my-ldap-server" + # port = 636 + # use_ssl = true + # start_tls = false + # ssl_skip_verify = false + # bind_dn = "uid=%s,ou=users,dc=myorg,dc=com" + +## Grafana's SMTP configuration +## NOTE: To enable, grafana.ini must be configured with smtp.enabled +## ref: http://docs.grafana.org/installation/configuration/#smtp +smtp: + # `existingSecret` is a reference to an existing secret containing the smtp configuration + # for Grafana. + existingSecret: "" + userKey: "user" + passwordKey: "password" + +## Sidecars that collect the configmaps with specified label and stores the included files them into the respective folders +## Requires at least Grafana 5 to work and can't be used together with parameters dashboardProviders, datasources and dashboards +sidecar: + image: + repository: rancher/mirrored-kiwigrid-k8s-sidecar + tag: 1.27.4 + sha: "" + imagePullPolicy: IfNotPresent + resources: {} +# limits: +# cpu: 100m +# memory: 100Mi +# requests: +# cpu: 50m +# memory: 50Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + # skipTlsVerify Set to true to skip tls verification for kube api calls + # skipTlsVerify: true + enableUniqueFilenames: false + readinessProbe: {} + livenessProbe: {} + # Log level default for all sidecars. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL. Defaults to INFO + # logLevel: INFO + alerts: + enabled: false + # Additional environment variables for the alerts sidecar + env: {} + # Do not reprocess already processed unchanged resources on k8s API reconnect. + # ignoreAlreadyProcessed: true + # label that the configmaps with alert are marked with + label: grafana_alert + # value of label that the configmaps with alert are set to + labelValue: "" + # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL. + # logLevel: INFO + # If specified, the sidecar will search for alert config-maps inside this namespace. + # Otherwise the namespace in which the sidecar is running will be used. + # It's also possible to specify ALL to search in all namespaces + searchNamespace: null + # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. + watchMethod: WATCH + # search in configmap, secret or both + resource: both + # watchServerTimeout: request to the server, asking it to cleanly close the connection after that. + # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S + # watchServerTimeout: 3600 + # + # watchClientTimeout: is a client-side timeout, configuring your local socket. + # If you have a network outage dropping all packets with no RST/FIN, + # this is how long your client waits before realizing & dropping the connection. + # defaults to 66sec (sic!) + # watchClientTimeout: 60 + # + # Endpoint to send request to reload alerts + reloadURL: "http://localhost:3000/api/admin/provisioning/alerting/reload" + # Absolute path to shell script to execute after a alert got reloaded + script: null + skipReload: false + # This is needed if skipReload is true, to load any alerts defined at startup time. + # Deploy the alert sidecar as an initContainer. + initAlerts: false + # Additional alert sidecar volume mounts + extraMounts: [] + # Sets the size limit of the alert sidecar emptyDir volume + sizeLimit: {} + dashboards: + enabled: false + # Additional environment variables for the dashboards sidecar + env: {} + ## "valueFrom" environment variable references that will be added to deployment pods. Name is templated. + ## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#envvarsource-v1-core + ## Renders in container spec as: + ## env: + ## ... + ## - name: + ## valueFrom: + ## + envValueFrom: {} + # ENV_NAME: + # configMapKeyRef: + # name: configmap-name + # key: value_key + # Do not reprocess already processed unchanged resources on k8s API reconnect. + # ignoreAlreadyProcessed: true + SCProvider: true + # label that the configmaps with dashboards are marked with + label: grafana_dashboard + # value of label that the configmaps with dashboards are set to + labelValue: "" + # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL. + # logLevel: INFO + # folder in the pod that should hold the collected dashboards (unless `defaultFolderName` is set) + folder: /tmp/dashboards + # The default folder name, it will create a subfolder under the `folder` and put dashboards in there instead + defaultFolderName: null + # Namespaces list. If specified, the sidecar will search for config-maps/secrets inside these namespaces. + # Otherwise the namespace in which the sidecar is running will be used. + # It's also possible to specify ALL to search in all namespaces. + searchNamespace: null + # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. + watchMethod: WATCH + # search in configmap, secret or both + resource: both + # If specified, the sidecar will look for annotation with this name to create folder and put graph here. + # You can use this parameter together with `provider.foldersFromFilesStructure`to annotate configmaps and create folder structure. + folderAnnotation: null + # Endpoint to send request to reload alerts + reloadURL: "http://localhost:3000/api/admin/provisioning/dashboards/reload" + # Absolute path to shell script to execute after a configmap got reloaded + script: null + skipReload: false + # watchServerTimeout: request to the server, asking it to cleanly close the connection after that. + # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S + # watchServerTimeout: 3600 + # + # watchClientTimeout: is a client-side timeout, configuring your local socket. + # If you have a network outage dropping all packets with no RST/FIN, + # this is how long your client waits before realizing & dropping the connection. + # defaults to 66sec (sic!) + # watchClientTimeout: 60 + # + # provider configuration that lets grafana manage the dashboards + provider: + # name of the provider, should be unique + name: sidecarProvider + # orgid as configured in grafana + orgid: 1 + # folder in which the dashboards should be imported in grafana + folder: '' + # folder UID. will be automatically generated if not specified + folderUid: '' + # type of the provider + type: file + # disableDelete to activate a import-only behaviour + disableDelete: false + # allow updating provisioned dashboards from the UI + allowUiUpdates: false + # allow Grafana to replicate dashboard structure from filesystem + foldersFromFilesStructure: false + # Additional dashboard sidecar volume mounts + extraMounts: [] + # Sets the size limit of the dashboard sidecar emptyDir volume + sizeLimit: {} + datasources: + enabled: false + # Additional environment variables for the datasourcessidecar + env: {} + ## "valueFrom" environment variable references that will be added to deployment pods. Name is templated. + ## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#envvarsource-v1-core + ## Renders in container spec as: + ## env: + ## ... + ## - name: + ## valueFrom: + ## + envValueFrom: {} + # ENV_NAME: + # configMapKeyRef: + # name: configmap-name + # key: value_key + # Do not reprocess already processed unchanged resources on k8s API reconnect. + # ignoreAlreadyProcessed: true + # label that the configmaps with datasources are marked with + label: grafana_datasource + # value of label that the configmaps with datasources are set to + labelValue: "" + # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL. + # logLevel: INFO + # If specified, the sidecar will search for datasource config-maps inside this namespace. + # Otherwise the namespace in which the sidecar is running will be used. + # It's also possible to specify ALL to search in all namespaces + searchNamespace: null + # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. + watchMethod: WATCH + # search in configmap, secret or both + resource: both + # watchServerTimeout: request to the server, asking it to cleanly close the connection after that. + # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S + # watchServerTimeout: 3600 + # + # watchClientTimeout: is a client-side timeout, configuring your local socket. + # If you have a network outage dropping all packets with no RST/FIN, + # this is how long your client waits before realizing & dropping the connection. + # defaults to 66sec (sic!) + # watchClientTimeout: 60 + # + # Endpoint to send request to reload datasources + reloadURL: "http://localhost:3000/api/admin/provisioning/datasources/reload" + # Absolute path to shell script to execute after a datasource got reloaded + script: null + skipReload: true + # This is needed if skipReload is true, to load any datasources defined at startup time. + # Deploy the datasources sidecar as an initContainer. + initDatasources: true + # Sets the size limit of the datasource sidecar emptyDir volume + sizeLimit: {} + plugins: + enabled: false + # Additional environment variables for the plugins sidecar + env: {} + # Do not reprocess already processed unchanged resources on k8s API reconnect. + # ignoreAlreadyProcessed: true + # label that the configmaps with plugins are marked with + label: grafana_plugin + # value of label that the configmaps with plugins are set to + labelValue: "" + # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL. + # logLevel: INFO + # If specified, the sidecar will search for plugin config-maps inside this namespace. + # Otherwise the namespace in which the sidecar is running will be used. + # It's also possible to specify ALL to search in all namespaces + searchNamespace: null + # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. + watchMethod: WATCH + # search in configmap, secret or both + resource: both + # watchServerTimeout: request to the server, asking it to cleanly close the connection after that. + # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S + # watchServerTimeout: 3600 + # + # watchClientTimeout: is a client-side timeout, configuring your local socket. + # If you have a network outage dropping all packets with no RST/FIN, + # this is how long your client waits before realizing & dropping the connection. + # defaults to 66sec (sic!) + # watchClientTimeout: 60 + # + # Endpoint to send request to reload plugins + reloadURL: "http://localhost:3000/api/admin/provisioning/plugins/reload" + # Absolute path to shell script to execute after a plugin got reloaded + script: null + skipReload: false + # Deploy the datasource sidecar as an initContainer in addition to a container. + # This is needed if skipReload is true, to load any plugins defined at startup time. + initPlugins: false + # Sets the size limit of the plugin sidecar emptyDir volume + sizeLimit: {} + notifiers: + enabled: false + # Additional environment variables for the notifierssidecar + env: {} + # Do not reprocess already processed unchanged resources on k8s API reconnect. + # ignoreAlreadyProcessed: true + # label that the configmaps with notifiers are marked with + label: grafana_notifier + # value of label that the configmaps with notifiers are set to + labelValue: "" + # Log level. Can be one of: DEBUG, INFO, WARN, ERROR, CRITICAL. + # logLevel: INFO + # If specified, the sidecar will search for notifier config-maps inside this namespace. + # Otherwise the namespace in which the sidecar is running will be used. + # It's also possible to specify ALL to search in all namespaces + searchNamespace: null + # Method to use to detect ConfigMap changes. With WATCH the sidecar will do a WATCH requests, with SLEEP it will list all ConfigMaps, then sleep for 60 seconds. + watchMethod: WATCH + # search in configmap, secret or both + resource: both + # watchServerTimeout: request to the server, asking it to cleanly close the connection after that. + # defaults to 60sec; much higher values like 3600 seconds (1h) are feasible for non-Azure K8S + # watchServerTimeout: 3600 + # + # watchClientTimeout: is a client-side timeout, configuring your local socket. + # If you have a network outage dropping all packets with no RST/FIN, + # this is how long your client waits before realizing & dropping the connection. + # defaults to 66sec (sic!) + # watchClientTimeout: 60 + # + # Endpoint to send request to reload notifiers + reloadURL: "http://localhost:3000/api/admin/provisioning/notifications/reload" + # Absolute path to shell script to execute after a notifier got reloaded + script: null + skipReload: false + # Deploy the notifier sidecar as an initContainer in addition to a container. + # This is needed if skipReload is true, to load any notifiers defined at startup time. + initNotifiers: false + # Sets the size limit of the notifier sidecar emptyDir volume + sizeLimit: {} + +## Override the deployment namespace +## +namespaceOverride: "" + +## Number of old ReplicaSets to retain +## +revisionHistoryLimit: 10 + +## Add a seperate remote image renderer deployment/service +imageRenderer: + deploymentStrategy: {} + # Enable the image-renderer deployment & service + enabled: false + replicas: 1 + autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 5 + targetCPU: "60" + targetMemory: "" + behavior: {} + image: + # image-renderer Image repository + repository: rancher/mirrored-grafana-grafana-image-renderer + # image-renderer Image tag + tag: 3.11.1 + # image-renderer Image sha (optional) + sha: "" + # image-renderer ImagePullPolicy + pullPolicy: Always + # extra environment variables + env: + HTTP_HOST: "0.0.0.0" + # RENDERING_ARGS: --no-sandbox,--disable-gpu,--window-size=1280x758 + # RENDERING_MODE: clustered + # IGNORE_HTTPS_ERRORS: true + + ## "valueFrom" environment variable references that will be added to deployment pods. Name is templated. + ## ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#envvarsource-v1-core + ## Renders in container spec as: + ## env: + ## ... + ## - name: + ## valueFrom: + ## + envValueFrom: {} + # ENV_NAME: + # configMapKeyRef: + # name: configmap-name + # key: value_key + + # image-renderer deployment serviceAccount + serviceAccountName: "" + # image-renderer deployment securityContext + securityContext: {} + # image-renderer deployment container securityContext + containerSecurityContext: + seccompProfile: + type: RuntimeDefault + capabilities: + drop: ['ALL'] + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + ## image-renderer pod annotation + podAnnotations: {} + # image-renderer deployment Host Aliases + hostAliases: [] + # image-renderer deployment priority class + priorityClassName: '' + service: + # Enable the image-renderer service + enabled: true + # image-renderer service port name + portName: 'http' + # image-renderer service port used by both service and deployment + port: 8081 + targetPort: 8081 + # Adds the appProtocol field to the image-renderer service. This allows to work with istio protocol selection. Ex: "http" or "tcp" + appProtocol: "" + serviceMonitor: + ## If true, a ServiceMonitor CRD is created for a prometheus operator + ## https://github.com/coreos/prometheus-operator + ## + enabled: false + path: /metrics + # namespace: monitoring (defaults to use the namespace this chart is deployed to) + labels: {} + interval: 1m + scheme: http + tlsConfig: {} + scrapeTimeout: 30s + relabelings: [] + # See: https://doc.crds.dev/github.com/prometheus-operator/kube-prometheus/monitoring.coreos.com/ServiceMonitor/v1@v0.11.0#spec-targetLabels + targetLabels: [] + # - targetLabel1 + # - targetLabel2 + # If https is enabled in Grafana, this needs to be set as 'https' to correctly configure the callback used in Grafana + grafanaProtocol: http + # In case a sub_path is used this needs to be added to the image renderer callback + grafanaSubPath: "" + # name of the image-renderer port on the pod + podPortName: http + # number of image-renderer replica sets to keep + revisionHistoryLimit: 10 + networkPolicy: + # Enable a NetworkPolicy to limit inbound traffic to only the created grafana pods + limitIngress: true + # Enable a NetworkPolicy to limit outbound traffic to only the created grafana pods + limitEgress: false + # Allow additional services to access image-renderer (eg. Prometheus operator when ServiceMonitor is enabled) + extraIngressSelectors: [] + resources: {} +# limits: +# cpu: 100m +# memory: 100Mi +# requests: +# cpu: 50m +# memory: 50Mi + ## Node labels for pod assignment + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + # + nodeSelector: {} + + ## Tolerations for pod assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + + ## Affinity for pod assignment (evaluated as template) + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## + affinity: {} + + ## Use an alternate scheduler, e.g. "stork". + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + # schedulerName: "default-scheduler" + + # Extra configmaps to mount in image-renderer pods + extraConfigmapMounts: [] + + # Extra secrets to mount in image-renderer pods + extraSecretMounts: [] + + # Extra volumes to mount in image-renderer pods + extraVolumeMounts: [] + + # Extra volumes for image-renderer pods + extraVolumes: [] + +networkPolicy: + ## @param networkPolicy.enabled Enable creation of NetworkPolicy resources. Only Ingress traffic is filtered for now. + ## + enabled: false + ## @param networkPolicy.allowExternal Don't require client label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## client label will have network access to grafana port defined. + ## When true, grafana will accept connections from any source + ## (with the correct destination port). + ## + ingress: true + ## @param networkPolicy.ingress When true enables the creation + ## an ingress network policy + ## + allowExternal: true + ## @param networkPolicy.explicitNamespacesSelector A Kubernetes LabelSelector to explicitly select namespaces from which traffic could be allowed + ## If explicitNamespacesSelector is missing or set to {}, only client Pods that are in the networkPolicy's namespace + ## and that match other criteria, the ones that have the good label, can reach the grafana. + ## But sometimes, we want the grafana to be accessible to clients from other namespaces, in this case, we can use this + ## LabelSelector to select these namespaces, note that the networkPolicy's namespace should also be explicitly added. + ## + ## Example: + ## explicitNamespacesSelector: + ## matchLabels: + ## role: frontend + ## matchExpressions: + ## - {key: role, operator: In, values: [frontend]} + ## + explicitNamespacesSelector: {} + ## + ## + ## + ## + ## + ## + egress: + ## @param networkPolicy.egress.enabled When enabled, an egress network policy will be + ## created allowing grafana to connect to external data sources from kubernetes cluster. + enabled: false + ## + ## @param networkPolicy.egress.blockDNSResolution When enabled, DNS resolution will be blocked + ## for all pods in the grafana namespace. + blockDNSResolution: false + ## + ## @param networkPolicy.egress.ports Add individual ports to be allowed by the egress + ports: [] + ## Add ports to the egress by specifying - port: + ## E.X. + ## - port: 80 + ## - port: 443 + ## + ## @param networkPolicy.egress.to Allow egress traffic to specific destinations + to: [] + ## Add destinations to the egress by specifying - ipBlock: + ## E.X. + ## to: + ## - namespaceSelector: + ## matchExpressions: + ## - {key: role, operator: In, values: [grafana]} + ## + ## + ## + ## + ## + +# Enable backward compatibility of kubernetes where version below 1.13 doesn't have the enableServiceLinks option +enableKubeBackwardCompatibility: false +useStatefulSet: false +# Create a dynamic manifests via values: +extraObjects: [] + # - apiVersion: "kubernetes-client.io/v1" + # kind: ExternalSecret + # metadata: + # name: grafana-secrets + # spec: + # backendType: gcpSecretsManager + # data: + # - key: grafana-admin-password + # name: adminPassword + +# assertNoLeakedSecrets is a helper function defined in _helpers.tpl that checks if secret +# values are not exposed in the rendered grafana.ini configmap. It is enabled by default. +# +# To pass values into grafana.ini without exposing them in a configmap, use variable expansion: +# https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#variable-expansion +# +# Alternatively, if you wish to allow secret values to be exposed in the rendered grafana.ini configmap, +# you can disable this check by setting assertNoLeakedSecrets to false. +assertNoLeakedSecrets: true diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/.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/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/Chart.yaml new file mode 100644 index 0000000000..97182329e6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: hardenedKubelet +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedKubelet/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/.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/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/Chart.yaml new file mode 100644 index 0000000000..61c466991e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: hardenedNodeExporter +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/hardenedNodeExporter/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/.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/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/Chart.yaml new file mode 100644 index 0000000000..94260bb4f4 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: k3sServer +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/k3sServer/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/.helmignore new file mode 100644 index 0000000000..f0c1319444 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/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/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/Chart.yaml new file mode 100644 index 0000000000..1360e832be --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/Chart.yaml @@ -0,0 +1,32 @@ +annotations: + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: Chart Source + url: https://github.com/prometheus-community/helm-charts + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-kube-state-metrics +apiVersion: v2 +appVersion: 2.12.0 +description: Install kube-state-metrics to generate and expose cluster-level metrics +home: https://github.com/kubernetes/kube-state-metrics/ +keywords: +- metric +- monitoring +- prometheus +- kubernetes +maintainers: +- email: tariq.ibrahim@mulesoft.com + name: tariq1890 +- email: manuel@rueg.eu + name: mrueg +- email: david@0xdc.me + name: dotdc +name: kube-state-metrics +sources: +- https://github.com/kubernetes/kube-state-metrics/ +type: application +version: 5.21.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/README.md new file mode 100644 index 0000000000..843be89e69 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/README.md @@ -0,0 +1,85 @@ +# kube-state-metrics Helm Chart + +Installs the [kube-state-metrics agent](https://github.com/kubernetes/kube-state-metrics). + +## Get Repository Info + +```console +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update +``` + +_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + + +## Install Chart + +```console +helm install [RELEASE_NAME] prometheus-community/kube-state-metrics [flags] +``` + +_See [configuration](#configuration) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Uninstall Chart + +```console +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +## Upgrading Chart + +```console +helm upgrade [RELEASE_NAME] prometheus-community/kube-state-metrics [flags] +``` + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### Migrating from stable/kube-state-metrics and kubernetes/kube-state-metrics + +You can upgrade in-place: + +1. [get repository info](#get-repository-info) +1. [upgrade](#upgrading-chart) your existing release name using the new chart repository + +## Upgrading to v3.0.0 + +v3.0.0 includes kube-state-metrics v2.0, see the [changelog](https://github.com/kubernetes/kube-state-metrics/blob/release-2.0/CHANGELOG.md) for major changes on the application-side. + +The upgraded chart now the following changes: + +* Dropped support for helm v2 (helm v3 or later is required) +* collectors key was renamed to resources +* namespace key was renamed to namespaces + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments: + +```console +helm show values prometheus-community/kube-state-metrics +``` + +### kube-rbac-proxy + +You can enable `kube-state-metrics` endpoint protection using `kube-rbac-proxy`. By setting `kubeRBACProxy.enabled: true`, this chart will deploy one RBAC proxy container per endpoint (metrics & telemetry). +To authorize access, authenticate your requests (via a `ServiceAccount` for example) with a `ClusterRole` attached such as: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: kube-state-metrics-read +rules: + - apiGroups: [ "" ] + resources: ["services/kube-state-metrics"] + verbs: + - get +``` + +See [kube-rbac-proxy examples](https://github.com/brancz/kube-rbac-proxy/tree/master/examples/resource-attributes) for more details. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/NOTES.txt b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/NOTES.txt new file mode 100644 index 0000000000..3589c24ec3 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/NOTES.txt @@ -0,0 +1,23 @@ +kube-state-metrics is a simple service that listens to the Kubernetes API server and generates metrics about the state of the objects. +The exposed metrics can be found here: +https://github.com/kubernetes/kube-state-metrics/blob/master/docs/README.md#exposed-metrics + +The metrics are exported on the HTTP endpoint /metrics on the listening port. +In your case, {{ template "kube-state-metrics.fullname" . }}.{{ template "kube-state-metrics.namespace" . }}.svc.cluster.local:{{ .Values.service.port }}/metrics + +They are served either as plaintext or protobuf depending on the Accept header. +They are designed to be consumed either by Prometheus itself or by a scraper that is compatible with scraping a Prometheus client endpoint. + +{{- if .Values.kubeRBACProxy.enabled}} + +kube-rbac-proxy endpoint protections is enabled: +- Metrics endpoints are now HTTPS +- Ensure that the client authenticates the requests (e.g. via service account) with the following role permissions: +``` +rules: + - apiGroups: [ "" ] + resources: ["services/{{ template "kube-state-metrics.fullname" . }}"] + verbs: + - get +``` +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/_helpers.tpl new file mode 100644 index 0000000000..ed277fbb53 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/_helpers.tpl @@ -0,0 +1,196 @@ +# Rancher +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +{{- define "monitoring_registry" -}} + {{- $temp_registry := (include "system_default_registry" .) -}} + {{- if $temp_registry -}} + {{- trimSuffix "/" $temp_registry -}} + {{- else -}} + {{- .Values.global.imageRegistry -}} + {{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "kube-state-metrics.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "kube-state-metrics.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "kube-state-metrics.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "kube-state-metrics.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "kube-state-metrics.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kube-state-metrics.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Generate basic labels +*/}} +{{- define "kube-state-metrics.labels" }} +helm.sh/chart: {{ template "kube-state-metrics.chart" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: metrics +app.kubernetes.io/part-of: {{ template "kube-state-metrics.name" . }} +{{- include "kube-state-metrics.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels }} +{{- end }} +{{- if .Values.releaseLabel }} +release: {{ .Release.Name }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "kube-state-metrics.selectorLabels" }} +{{- if .Values.selectorOverride }} +{{ toYaml .Values.selectorOverride }} +{{- else }} +app.kubernetes.io/name: {{ include "kube-state-metrics.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} +{{- end }} + +{{/* Sets default scrape limits for servicemonitor */}} +{{- define "servicemonitor.scrapeLimits" -}} +{{- with .sampleLimit }} +sampleLimit: {{ . }} +{{- end }} +{{- with .targetLimit }} +targetLimit: {{ . }} +{{- end }} +{{- with .labelLimit }} +labelLimit: {{ . }} +{{- end }} +{{- with .labelNameLengthLimit }} +labelNameLengthLimit: {{ . }} +{{- end }} +{{- with .labelValueLengthLimit }} +labelValueLengthLimit: {{ . }} +{{- end }} +{{- end -}} + +{{/* +Formats imagePullSecrets. Input is (dict "Values" .Values "imagePullSecrets" .{specific imagePullSecrets}) +*/}} +{{- define "kube-state-metrics.imagePullSecrets" -}} +{{- range (concat .Values.global.imagePullSecrets .imagePullSecrets) }} + {{- if eq (typeOf .) "map[string]interface {}" }} +- {{ toYaml . | trim }} + {{- else }} +- name: {{ . }} + {{- end }} +{{- end }} +{{- end -}} + +{{/* +The image to use for kube-state-metrics +*/}} +{{- define "kube-state-metrics.image" -}} +{{- $registry := (include "monitoring_registry" .) }} +{{- if .Values.image.sha }} +{{- if $registry }} +{{- printf "%s/%s:%s@%s" $registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) .Values.image.sha }} +{{- else }} +{{- printf "%s/%s:%s@%s" .Values.image.registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) .Values.image.sha }} +{{- end }} +{{- else }} +{{- if $registry }} +{{- printf "%s/%s:%s" $registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }} +{{- else }} +{{- printf "%s/%s:%s" .Values.image.registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +The image to use for kubeRBACProxy +*/}} +{{- define "kubeRBACProxy.image" -}} +{{- $registry := (include "monitoring_registry" .) }} +{{- if .Values.kubeRBACProxy.image.sha }} +{{- if $registry }} +{{- printf "%s/%s:%s@%s" $registry .Values.kubeRBACProxy.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.kubeRBACProxy.image.tag) .Values.kubeRBACProxy.image.sha }} +{{- else }} +{{- printf "%s/%s:%s@%s" .Values.kubeRBACProxy.image.registry .Values.kubeRBACProxy.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.kubeRBACProxy.image.tag) .Values.kubeRBACProxy.image.sha }} +{{- end }} +{{- else }} +{{- if $registry }} +{{- printf "%s/%s:%s" $registry .Values.kubeRBACProxy.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.kubeRBACProxy.image.tag) }} +{{- else }} +{{- printf "%s/%s:%s" .Values.kubeRBACProxy.image.registry .Values.kubeRBACProxy.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.kubeRBACProxy.image.tag) }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml new file mode 100644 index 0000000000..025cd47a88 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.networkPolicy.enabled (eq .Values.networkPolicy.flavor "cilium") }} +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + {{- if .Values.annotations }} + annotations: + {{ toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +spec: + endpointSelector: + matchLabels: + {{- include "kube-state-metrics.selectorLabels" . | indent 6 }} + egress: + {{- if and .Values.networkPolicy.cilium .Values.networkPolicy.cilium.kubeApiServerSelector }} + {{ toYaml .Values.networkPolicy.cilium.kubeApiServerSelector | nindent 6 }} + {{- else }} + - toEntities: + - kube-apiserver + {{- end }} + ingress: + - toPorts: + - ports: + - port: {{ .Values.service.port | quote }} + protocol: TCP + {{- if .Values.selfMonitor.enabled }} + - port: {{ .Values.selfMonitor.telemetryPort | default 8081 | quote }} + protocol: TCP + {{ end }} +{{ end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/clusterrolebinding.yaml new file mode 100644 index 0000000000..cf9f628d04 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.rbac.create .Values.rbac.useClusterRole -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: {{ template "kube-state-metrics.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole +{{- if .Values.rbac.useExistingRole }} + name: {{ .Values.rbac.useExistingRole }} +{{- else }} + name: {{ template "kube-state-metrics.fullname" . }} +{{- end }} +subjects: +- kind: ServiceAccount + name: {{ template "kube-state-metrics.serviceAccountName" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/crs-configmap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/crs-configmap.yaml new file mode 100644 index 0000000000..d38a75a51d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/crs-configmap.yaml @@ -0,0 +1,16 @@ +{{- if .Values.customResourceState.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "kube-state-metrics.fullname" . }}-customresourcestate-config + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + {{- if .Values.annotations }} + annotations: + {{ toYaml .Values.annotations | nindent 4 }} + {{- end }} +data: + config.yaml: | + {{- toYaml .Values.customResourceState.config | nindent 4 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/deployment.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/deployment.yaml new file mode 100644 index 0000000000..2c63048cc6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/deployment.yaml @@ -0,0 +1,313 @@ +apiVersion: apps/v1 +{{- if .Values.autosharding.enabled }} +kind: StatefulSet +{{- else }} +kind: Deployment +{{- end }} +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + {{- if .Values.annotations }} + annotations: +{{ toYaml .Values.annotations | indent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "kube-state-metrics.selectorLabels" . | indent 6 }} + replicas: {{ .Values.replicas }} + {{- if not .Values.autosharding.enabled }} + strategy: + type: {{ .Values.updateStrategy | default "RollingUpdate" }} + {{- end }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + {{- if .Values.autosharding.enabled }} + serviceName: {{ template "kube-state-metrics.fullname" . }} + volumeClaimTemplates: [] + {{- end }} + template: + metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 8 }} + {{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + spec: + automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} + hostNetwork: {{ .Values.hostNetwork }} + serviceAccountName: {{ template "kube-state-metrics.serviceAccountName" . }} + {{- if .Values.securityContext.enabled }} + securityContext: {{- omit .Values.securityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName }} + {{- end }} + {{- with .Values.initContainers }} + initContainers: + {{- toYaml . | nindent 6 }} + {{- end }} + containers: + {{- $servicePort := ternary 9090 (.Values.service.port | default 8080) .Values.kubeRBACProxy.enabled}} + {{- $telemetryPort := ternary 9091 (.Values.selfMonitor.telemetryPort | default 8081) .Values.kubeRBACProxy.enabled}} + - name: {{ template "kube-state-metrics.name" . }} + {{- if .Values.autosharding.enabled }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- end }} + args: + {{- if .Values.extraArgs }} + {{- .Values.extraArgs | toYaml | nindent 8 }} + {{- end }} + - --port={{ $servicePort }} + {{- if .Values.collectors }} + - --resources={{ .Values.collectors | join "," }} + {{- end }} + {{- if .Values.metricLabelsAllowlist }} + - --metric-labels-allowlist={{ .Values.metricLabelsAllowlist | join "," }} + {{- end }} + {{- if .Values.metricAnnotationsAllowList }} + - --metric-annotations-allowlist={{ .Values.metricAnnotationsAllowList | join "," }} + {{- end }} + {{- if .Values.metricAllowlist }} + - --metric-allowlist={{ .Values.metricAllowlist | join "," }} + {{- end }} + {{- if .Values.metricDenylist }} + - --metric-denylist={{ .Values.metricDenylist | join "," }} + {{- end }} + {{- $namespaces := list }} + {{- if .Values.namespaces }} + {{- range $ns := join "," .Values.namespaces | split "," }} + {{- $namespaces = append $namespaces (tpl $ns $) }} + {{- end }} + {{- end }} + {{- if .Values.releaseNamespace }} + {{- $namespaces = append $namespaces ( include "kube-state-metrics.namespace" . ) }} + {{- end }} + {{- if $namespaces }} + - --namespaces={{ $namespaces | mustUniq | join "," }} + {{- end }} + {{- if .Values.namespacesDenylist }} + - --namespaces-denylist={{ tpl (.Values.namespacesDenylist | join ",") $ }} + {{- end }} + {{- if .Values.autosharding.enabled }} + - --pod=$(POD_NAME) + - --pod-namespace=$(POD_NAMESPACE) + {{- end }} + {{- if .Values.kubeconfig.enabled }} + - --kubeconfig=/opt/k8s/.kube/config + {{- end }} + {{- if .Values.kubeRBACProxy.enabled }} + - --telemetry-host=127.0.0.1 + - --telemetry-port={{ $telemetryPort }} + {{- else }} + {{- if .Values.selfMonitor.telemetryHost }} + - --telemetry-host={{ .Values.selfMonitor.telemetryHost }} + {{- end }} + {{- if .Values.selfMonitor.telemetryPort }} + - --telemetry-port={{ $telemetryPort }} + {{- end }} + {{- end }} + {{- if .Values.customResourceState.enabled }} + - --custom-resource-state-config-file=/etc/customresourcestate/config.yaml + {{- end }} + {{- if or (.Values.kubeconfig.enabled) (.Values.customResourceState.enabled) (.Values.volumeMounts) }} + volumeMounts: + {{- if .Values.kubeconfig.enabled }} + - name: kubeconfig + mountPath: /opt/k8s/.kube/ + readOnly: true + {{- end }} + {{- if .Values.customResourceState.enabled }} + - name: customresourcestate-config + mountPath: /etc/customresourcestate + readOnly: true + {{- end }} + {{- if .Values.volumeMounts }} +{{ toYaml .Values.volumeMounts | indent 8 }} + {{- end }} + {{- end }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + image: {{ include "kube-state-metrics.image" . }} + {{- if eq .Values.kubeRBACProxy.enabled false }} + ports: + - containerPort: {{ .Values.service.port | default 8080}} + name: "http" + {{- if .Values.selfMonitor.enabled }} + - containerPort: {{ $telemetryPort }} + name: "metrics" + {{- end }} + {{- end }} + livenessProbe: + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + httpGet: + {{- if .Values.hostNetwork }} + host: 127.0.0.1 + {{- end }} + httpHeaders: + {{- range $_, $header := .Values.livenessProbe.httpGet.httpHeaders }} + - name: {{ $header.name }} + value: {{ $header.value }} + {{- end }} + path: /healthz + port: {{ $servicePort }} + scheme: {{ upper .Values.livenessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + readinessProbe: + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + {{- if .Values.hostNetwork }} + host: 127.0.0.1 + {{- end }} + httpHeaders: + {{- range $_, $header := .Values.readinessProbe.httpGet.httpHeaders }} + - name: {{ $header.name }} + value: {{ $header.value }} + {{- end }} + path: / + port: {{ $servicePort }} + scheme: {{ upper .Values.readinessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + resources: +{{ toYaml .Values.resources | indent 10 }} +{{- if .Values.containerSecurityContext }} + securityContext: +{{ toYaml .Values.containerSecurityContext | indent 10 }} +{{- end }} + {{- if .Values.kubeRBACProxy.enabled }} + - name: kube-rbac-proxy-http + args: + {{- if .Values.kubeRBACProxy.extraArgs }} + {{- .Values.kubeRBACProxy.extraArgs | toYaml | nindent 8 }} + {{- end }} + - --secure-listen-address=:{{ .Values.service.port | default 8080}} + - --upstream=http://127.0.0.1:{{ $servicePort }}/ + - --proxy-endpoints-port=8888 + - --config-file=/etc/kube-rbac-proxy-config/config-file.yaml + volumeMounts: + - name: kube-rbac-proxy-config + mountPath: /etc/kube-rbac-proxy-config + {{- with .Values.kubeRBACProxy.volumeMounts }} + {{- toYaml . | nindent 10 }} + {{- end }} + imagePullPolicy: {{ .Values.kubeRBACProxy.image.pullPolicy }} + image: {{ include "kubeRBACProxy.image" . }} + ports: + - containerPort: {{ .Values.service.port | default 8080}} + name: "http" + - containerPort: 8888 + name: "http-healthz" + readinessProbe: + httpGet: + scheme: HTTPS + port: 8888 + path: healthz + initialDelaySeconds: 5 + timeoutSeconds: 5 + {{- if .Values.kubeRBACProxy.resources }} + resources: +{{ toYaml .Values.kubeRBACProxy.resources | indent 10 }} +{{- end }} +{{- if .Values.kubeRBACProxy.containerSecurityContext }} + securityContext: +{{ toYaml .Values.kubeRBACProxy.containerSecurityContext | indent 10 }} +{{- end }} + {{- if .Values.selfMonitor.enabled }} + - name: kube-rbac-proxy-telemetry + args: + {{- if .Values.kubeRBACProxy.extraArgs }} + {{- .Values.kubeRBACProxy.extraArgs | toYaml | nindent 8 }} + {{- end }} + - --secure-listen-address=:{{ .Values.selfMonitor.telemetryPort | default 8081 }} + - --upstream=http://127.0.0.1:{{ $telemetryPort }}/ + - --proxy-endpoints-port=8889 + - --config-file=/etc/kube-rbac-proxy-config/config-file.yaml + volumeMounts: + - name: kube-rbac-proxy-config + mountPath: /etc/kube-rbac-proxy-config + {{- with .Values.kubeRBACProxy.volumeMounts }} + {{- toYaml . | nindent 10 }} + {{- end }} + imagePullPolicy: {{ .Values.kubeRBACProxy.image.pullPolicy }} + image: {{ include "kubeRBACProxy.image" . }} + ports: + - containerPort: {{ .Values.selfMonitor.telemetryPort | default 8081 }} + name: "metrics" + - containerPort: 8889 + name: "metrics-healthz" + readinessProbe: + httpGet: + scheme: HTTPS + port: 8889 + path: healthz + initialDelaySeconds: 5 + timeoutSeconds: 5 + {{- if .Values.kubeRBACProxy.resources }} + resources: +{{ toYaml .Values.kubeRBACProxy.resources | indent 10 }} +{{- end }} +{{- if .Values.kubeRBACProxy.containerSecurityContext }} + securityContext: +{{ toYaml .Values.kubeRBACProxy.containerSecurityContext | indent 10 }} +{{- end }} + {{- end }} + {{- end }} + {{- with .Values.containers }} + {{- toYaml . | nindent 6 }} + {{- end }} +{{- if or .Values.imagePullSecrets .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- include "kube-state-metrics.imagePullSecrets" (dict "Values" .Values "imagePullSecrets" .Values.imagePullSecrets) | indent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} + {{- if .Values.nodeSelector }} +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} + {{- if .Values.tolerations }} +{{ toYaml .Values.tolerations | indent 8 }} + {{- end }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.topologySpreadConstraints | indent 8 }} + {{- end }} + {{- if or (.Values.kubeconfig.enabled) (.Values.customResourceState.enabled) (.Values.volumes) (.Values.kubeRBACProxy.enabled) }} + volumes: + {{- if .Values.kubeconfig.enabled}} + - name: kubeconfig + secret: + secretName: {{ template "kube-state-metrics.fullname" . }}-kubeconfig + {{- end }} + {{- if .Values.kubeRBACProxy.enabled}} + - name: kube-rbac-proxy-config + configMap: + name: {{ template "kube-state-metrics.fullname" . }}-rbac-config + {{- end }} + {{- if .Values.customResourceState.enabled}} + - name: customresourcestate-config + configMap: + name: {{ template "kube-state-metrics.fullname" . }}-customresourcestate-config + {{- end }} + {{- if .Values.volumes }} +{{ toYaml .Values.volumes | indent 8 }} + {{- end }} + {{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/extra-manifests.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/extra-manifests.yaml new file mode 100644 index 0000000000..567f7bf329 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/extra-manifests.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraManifests }} +--- +{{ tpl (toYaml .) $ }} +{{ end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/kubeconfig-secret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/kubeconfig-secret.yaml new file mode 100644 index 0000000000..6af0084502 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/kubeconfig-secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.kubeconfig.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kube-state-metrics.fullname" . }}-kubeconfig + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +type: Opaque +data: + config: '{{ .Values.kubeconfig.secret }}' +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/networkpolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/networkpolicy.yaml new file mode 100644 index 0000000000..309b38ec54 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/networkpolicy.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.networkPolicy.enabled (eq .Values.networkPolicy.flavor "kubernetes") }} +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + {{- if .Values.annotations }} + annotations: + {{ toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +spec: + {{- if .Values.networkPolicy.egress }} + ## Deny all egress by default + egress: + {{- toYaml .Values.networkPolicy.egress | nindent 4 }} + {{- end }} + ingress: + {{- if .Values.networkPolicy.ingress }} + {{- toYaml .Values.networkPolicy.ingress | nindent 4 }} + {{- else }} + ## Allow ingress on default ports by default + - ports: + - port: {{ .Values.service.port | default 8080 }} + protocol: TCP + {{- if .Values.selfMonitor.enabled }} + {{- $telemetryPort := ternary 9091 (.Values.selfMonitor.telemetryPort | default 8081) .Values.kubeRBACProxy.enabled}} + - port: {{ $telemetryPort }} + protocol: TCP + {{- end }} + {{- end }} + podSelector: + {{- if .Values.networkPolicy.podSelector }} + {{- toYaml .Values.networkPolicy.podSelector | nindent 4 }} + {{- else }} + matchLabels: + {{- include "kube-state-metrics.selectorLabels" . | indent 6 }} + {{- end }} + policyTypes: + - Ingress + - Egress +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/pdb.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/pdb.yaml new file mode 100644 index 0000000000..3771b511de --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/pdb.yaml @@ -0,0 +1,18 @@ +{{- if .Values.podDisruptionBudget -}} +{{ if $.Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" -}} +apiVersion: policy/v1 +{{- else -}} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +spec: + selector: + matchLabels: + app.kubernetes.io/name: {{ template "kube-state-metrics.name" . }} +{{ toYaml .Values.podDisruptionBudget | indent 2 }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/podsecuritypolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/podsecuritypolicy.yaml new file mode 100644 index 0000000000..8905e113e8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/podsecuritypolicy.yaml @@ -0,0 +1,39 @@ +{{- if and .Values.podSecurityPolicy.enabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +{{- if .Values.podSecurityPolicy.annotations }} + annotations: +{{ toYaml .Values.podSecurityPolicy.annotations | indent 4 }} +{{- end }} +spec: + privileged: false + volumes: + - 'secret' +{{- if .Values.podSecurityPolicy.additionalVolumes }} +{{ toYaml .Values.podSecurityPolicy.additionalVolumes | indent 4 }} +{{- end }} + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/psp-clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/psp-clusterrole.yaml new file mode 100644 index 0000000000..654e4a3d57 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/psp-clusterrole.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.podSecurityPolicy.enabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: psp-{{ template "kube-state-metrics.fullname" . }} +rules: +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare "> 1.15.0-0" $kubeTargetVersion }} +- apiGroups: ['policy'] +{{- else }} +- apiGroups: ['extensions'] +{{- end }} + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "kube-state-metrics.fullname" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml new file mode 100644 index 0000000000..5b62a18bdf --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.podSecurityPolicy.enabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: psp-{{ template "kube-state-metrics.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: psp-{{ template "kube-state-metrics.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "kube-state-metrics.serviceAccountName" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/rbac-configmap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/rbac-configmap.yaml new file mode 100644 index 0000000000..671dc9d660 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/rbac-configmap.yaml @@ -0,0 +1,22 @@ +{{- if .Values.kubeRBACProxy.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "kube-state-metrics.fullname" . }}-rbac-config + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + {{- if .Values.annotations }} + annotations: + {{ toYaml .Values.annotations | nindent 4 }} + {{- end }} +data: + config-file.yaml: |+ + authorization: + resourceAttributes: + namespace: {{ template "kube-state-metrics.namespace" . }} + apiVersion: v1 + resource: services + subresource: {{ template "kube-state-metrics.fullname" . }} + name: {{ template "kube-state-metrics.fullname" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/role.yaml new file mode 100644 index 0000000000..0170878376 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/role.yaml @@ -0,0 +1,215 @@ +{{- if not (kindIs "slice" .Values.collectors) }} +{{- fail "Collectors need to be a List since kube-state-metrics chart 3.2.2. Please check README for more information."}} +{{- end }} +{{- if and (eq .Values.rbac.create true) (not .Values.rbac.useExistingRole) -}} +{{- range (ternary (join "," .Values.namespaces | split "," ) (list "") (eq $.Values.rbac.useClusterRole false)) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +{{- if eq $.Values.rbac.useClusterRole false }} +kind: Role +{{- else }} +kind: ClusterRole +{{- end }} +metadata: + labels: + {{- include "kube-state-metrics.labels" $ | indent 4 }} + name: {{ template "kube-state-metrics.fullname" $ }} +{{- if eq $.Values.rbac.useClusterRole false }} + namespace: {{ . }} +{{- end }} +rules: +{{ if has "certificatesigningrequests" $.Values.collectors }} +- apiGroups: ["certificates.k8s.io"] + resources: + - certificatesigningrequests + verbs: ["list", "watch"] +{{ end -}} +{{ if has "configmaps" $.Values.collectors }} +- apiGroups: [""] + resources: + - configmaps + verbs: ["list", "watch"] +{{ end -}} +{{ if has "cronjobs" $.Values.collectors }} +- apiGroups: ["batch"] + resources: + - cronjobs + verbs: ["list", "watch"] +{{ end -}} +{{ if has "daemonsets" $.Values.collectors }} +- apiGroups: ["extensions", "apps"] + resources: + - daemonsets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "deployments" $.Values.collectors }} +- apiGroups: ["extensions", "apps"] + resources: + - deployments + verbs: ["list", "watch"] +{{ end -}} +{{ if has "endpoints" $.Values.collectors }} +- apiGroups: [""] + resources: + - endpoints + verbs: ["list", "watch"] +{{ end -}} +{{ if has "endpointslices" $.Values.collectors }} +- apiGroups: ["discovery.k8s.io"] + resources: + - endpointslices + verbs: ["list", "watch"] +{{ end -}} +{{ if has "horizontalpodautoscalers" $.Values.collectors }} +- apiGroups: ["autoscaling"] + resources: + - horizontalpodautoscalers + verbs: ["list", "watch"] +{{ end -}} +{{ if has "ingresses" $.Values.collectors }} +- apiGroups: ["extensions", "networking.k8s.io"] + resources: + - ingresses + verbs: ["list", "watch"] +{{ end -}} +{{ if has "jobs" $.Values.collectors }} +- apiGroups: ["batch"] + resources: + - jobs + verbs: ["list", "watch"] +{{ end -}} +{{ if has "leases" $.Values.collectors }} +- apiGroups: ["coordination.k8s.io"] + resources: + - leases + verbs: ["list", "watch"] +{{ end -}} +{{ if has "limitranges" $.Values.collectors }} +- apiGroups: [""] + resources: + - limitranges + verbs: ["list", "watch"] +{{ end -}} +{{ if has "mutatingwebhookconfigurations" $.Values.collectors }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: + - mutatingwebhookconfigurations + verbs: ["list", "watch"] +{{ end -}} +{{ if has "namespaces" $.Values.collectors }} +- apiGroups: [""] + resources: + - namespaces + verbs: ["list", "watch"] +{{ end -}} +{{ if has "networkpolicies" $.Values.collectors }} +- apiGroups: ["networking.k8s.io"] + resources: + - networkpolicies + verbs: ["list", "watch"] +{{ end -}} +{{ if has "nodes" $.Values.collectors }} +- apiGroups: [""] + resources: + - nodes + verbs: ["list", "watch"] +{{ end -}} +{{ if has "persistentvolumeclaims" $.Values.collectors }} +- apiGroups: [""] + resources: + - persistentvolumeclaims + verbs: ["list", "watch"] +{{ end -}} +{{ if has "persistentvolumes" $.Values.collectors }} +- apiGroups: [""] + resources: + - persistentvolumes + verbs: ["list", "watch"] +{{ end -}} +{{ if has "poddisruptionbudgets" $.Values.collectors }} +- apiGroups: ["policy"] + resources: + - poddisruptionbudgets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "pods" $.Values.collectors }} +- apiGroups: [""] + resources: + - pods + verbs: ["list", "watch"] +{{ end -}} +{{ if has "replicasets" $.Values.collectors }} +- apiGroups: ["extensions", "apps"] + resources: + - replicasets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "replicationcontrollers" $.Values.collectors }} +- apiGroups: [""] + resources: + - replicationcontrollers + verbs: ["list", "watch"] +{{ end -}} +{{ if has "resourcequotas" $.Values.collectors }} +- apiGroups: [""] + resources: + - resourcequotas + verbs: ["list", "watch"] +{{ end -}} +{{ if has "secrets" $.Values.collectors }} +- apiGroups: [""] + resources: + - secrets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "services" $.Values.collectors }} +- apiGroups: [""] + resources: + - services + verbs: ["list", "watch"] +{{ end -}} +{{ if has "statefulsets" $.Values.collectors }} +- apiGroups: ["apps"] + resources: + - statefulsets + verbs: ["list", "watch"] +{{ end -}} +{{ if has "storageclasses" $.Values.collectors }} +- apiGroups: ["storage.k8s.io"] + resources: + - storageclasses + verbs: ["list", "watch"] +{{ end -}} +{{ if has "validatingwebhookconfigurations" $.Values.collectors }} +- apiGroups: ["admissionregistration.k8s.io"] + resources: + - validatingwebhookconfigurations + verbs: ["list", "watch"] +{{ end -}} +{{ if has "volumeattachments" $.Values.collectors }} +- apiGroups: ["storage.k8s.io"] + resources: + - volumeattachments + verbs: ["list", "watch"] +{{ end -}} +{{- if $.Values.kubeRBACProxy.enabled }} +- apiGroups: ["authentication.k8s.io"] + resources: + - tokenreviews + verbs: ["create"] +- apiGroups: ["authorization.k8s.io"] + resources: + - subjectaccessreviews + verbs: ["create"] +{{- end }} +{{- if $.Values.customResourceState.enabled }} +- apiGroups: ["apiextensions.k8s.io"] + resources: + - customresourcedefinitions + verbs: ["list", "watch"] +{{- end }} +{{ if $.Values.rbac.extraRules }} +{{ toYaml $.Values.rbac.extraRules }} +{{ end }} +{{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/rolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/rolebinding.yaml new file mode 100644 index 0000000000..330651b73f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/rolebinding.yaml @@ -0,0 +1,24 @@ +{{- if and (eq .Values.rbac.create true) (eq .Values.rbac.useClusterRole false) -}} +{{- range (join "," $.Values.namespaces) | split "," }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + {{- include "kube-state-metrics.labels" $ | indent 4 }} + name: {{ template "kube-state-metrics.fullname" $ }} + namespace: {{ . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role +{{- if (not $.Values.rbac.useExistingRole) }} + name: {{ template "kube-state-metrics.fullname" $ }} +{{- else }} + name: {{ $.Values.rbac.useExistingRole }} +{{- end }} +subjects: +- kind: ServiceAccount + name: {{ template "kube-state-metrics.serviceAccountName" $ }} + namespace: {{ template "kube-state-metrics.namespace" $ }} +{{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/service.yaml new file mode 100644 index 0000000000..90c235148f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/service.yaml @@ -0,0 +1,53 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + annotations: + {{- if .Values.prometheusScrape }} + prometheus.io/scrape: '{{ .Values.prometheusScrape }}' + {{- end }} + {{- if .Values.service.annotations }} + {{- toYaml .Values.service.annotations | nindent 4 }} + {{- end }} +spec: + type: "{{ .Values.service.type }}" + {{- if .Values.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.service.ipDualStack.ipFamilyPolicy }} + {{- end }} + ports: + - name: "http" + protocol: TCP + port: {{ .Values.service.port | default 8080}} + {{- if .Values.service.nodePort }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + targetPort: {{ .Values.service.port | default 8080}} + {{ if .Values.selfMonitor.enabled }} + - name: "metrics" + protocol: TCP + port: {{ .Values.selfMonitor.telemetryPort | default 8081 }} + targetPort: {{ .Values.selfMonitor.telemetryPort | default 8081 }} + {{- if .Values.selfMonitor.telemetryNodePort }} + nodePort: {{ .Values.selfMonitor.telemetryNodePort }} + {{- end }} + {{ end }} +{{- if .Values.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.service.loadBalancerIP }}" +{{- end }} +{{- if .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.service.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} +{{- end }} +{{- if .Values.autosharding.enabled }} + clusterIP: None +{{- else if .Values.service.clusterIP }} + clusterIP: "{{ .Values.service.clusterIP }}" +{{- end }} + selector: + {{- include "kube-state-metrics.selectorLabels" . | indent 4 }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/serviceaccount.yaml new file mode 100644 index 0000000000..c302bc7ca0 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +metadata: + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + name: {{ template "kube-state-metrics.serviceAccountName" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- if .Values.serviceAccount.annotations }} + annotations: +{{ toYaml .Values.serviceAccount.annotations | indent 4 }} +{{- end }} +{{- if or .Values.serviceAccount.imagePullSecrets .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- include "kube-state-metrics.imagePullSecrets" (dict "Values" .Values "imagePullSecrets" .Values.serviceAccount.imagePullSecrets) | indent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/servicemonitor.yaml new file mode 100644 index 0000000000..577981b080 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/servicemonitor.yaml @@ -0,0 +1,126 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} + {{- with .Values.prometheus.monitor.additionalLabels }} + {{- tpl (toYaml . | nindent 4) $ }} + {{- end }} + {{- with .Values.prometheus.monitor.annotations }} + annotations: + {{- tpl (toYaml . | nindent 4) $ }} + {{- end }} +spec: + jobLabel: {{ default "app.kubernetes.io/name" .Values.prometheus.monitor.jobLabel }} + {{- with .Values.prometheus.monitor.targetLabels }} + targetLabels: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + {{- with .Values.prometheus.monitor.podTargetLabels }} + podTargetLabels: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + {{- include "servicemonitor.scrapeLimits" .Values.prometheus.monitor | indent 2 }} + {{- if .Values.prometheus.monitor.namespaceSelector }} + namespaceSelector: + matchNames: + {{- with .Values.prometheus.monitor.namespaceSelector }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} + selector: + matchLabels: + {{- with .Values.prometheus.monitor.selectorOverride }} + {{- toYaml . | nindent 6 }} + {{- else }} + {{- include "kube-state-metrics.selectorLabels" . | indent 6 }} + {{- end }} + endpoints: + - port: http + {{- if or .Values.prometheus.monitor.http.interval .Values.prometheus.monitor.interval }} + interval: {{ .Values.prometheus.monitor.http.interval | default .Values.prometheus.monitor.interval }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.scrapeTimeout .Values.prometheus.monitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.prometheus.monitor.http.scrapeTimeout | default .Values.prometheus.monitor.scrapeTimeout }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.proxyUrl .Values.prometheus.monitor.proxyUrl }} + proxyUrl: {{ .Values.prometheus.monitor.http.proxyUrl | default .Values.prometheus.monitor.proxyUrl }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.enableHttp2 .Values.prometheus.monitor.enableHttp2 }} + enableHttp2: {{ .Values.prometheus.monitor.http.enableHttp2 | default .Values.prometheus.monitor.enableHttp2 }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.honorLabels .Values.prometheus.monitor.honorLabels }} + honorLabels: true + {{- end }} + metricRelabelings: + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName }} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.metricRelabelings .Values.prometheus.monitor.metricRelabelings }} + {{- toYaml (.Values.prometheus.monitor.http.metricRelabelings | default .Values.prometheus.monitor.metricRelabelings) | nindent 8 }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.relabelings .Values.prometheus.monitor.relabelings }} + relabelings: + {{- toYaml (.Values.prometheus.monitor.http.relabelings | default .Values.prometheus.monitor.relabelings) | nindent 8 }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.scheme .Values.prometheus.monitor.scheme }} + scheme: {{ .Values.prometheus.monitor.http.scheme | default .Values.prometheus.monitor.scheme }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.tlsConfig .Values.prometheus.monitor.tlsConfig }} + tlsConfig: + {{- toYaml (.Values.prometheus.monitor.http.tlsConfig | default .Values.prometheus.monitor.tlsConfig) | nindent 8 }} + {{- end }} + {{- if or .Values.prometheus.monitor.http.bearerTokenFile .Values.prometheus.monitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.prometheus.monitor.http.bearerTokenFile | default .Values.prometheus.monitor.bearerTokenFile }} + {{- end }} + {{- with (.Values.prometheus.monitor.http.bearerTokenSecret | default .Values.prometheus.monitor.bearerTokenSecret) }} + bearerTokenSecret: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.selfMonitor.enabled }} + - port: metrics + {{- if or .Values.prometheus.monitor.metrics.interval .Values.prometheus.monitor.interval }} + interval: {{ .Values.prometheus.monitor.metrics.interval | default .Values.prometheus.monitor.interval }} + {{- end }} + {{- if or .Values.prometheus.monitor.metrics.scrapeTimeout .Values.prometheus.monitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.prometheus.monitor.metrics.scrapeTimeout | default .Values.prometheus.monitor.scrapeTimeout }} + {{- end }} + {{- if or .Values.prometheus.monitor.metrics.proxyUrl .Values.prometheus.monitor.proxyUrl }} + proxyUrl: {{ .Values.prometheus.monitor.metrics.proxyUrl | default .Values.prometheus.monitor.proxyUrl }} + {{- end }} + {{- if or .Values.prometheus.monitor.metrics.enableHttp2 .Values.prometheus.monitor.enableHttp2 }} + enableHttp2: {{ .Values.prometheus.monitor.metrics.enableHttp2 | default .Values.prometheus.monitor.enableHttp2 }} + {{- end }} + {{- if or .Values.prometheus.monitor.metrics.honorLabels .Values.prometheus.monitor.honorLabels }} + honorLabels: true + {{- end }} + {{- if or .Values.prometheus.monitor.metrics.relabelings .Values.prometheus.monitor.relabelings }} + relabelings: + {{- toYaml (.Values.prometheus.monitor.metrics.relabelings | default .Values.prometheus.monitor.relabelings) | nindent 8 }} + {{- end }} + {{- if or .Values.prometheus.monitor.metrics.scheme .Values.prometheus.monitor.scheme }} + scheme: {{ .Values.prometheus.monitor.metrics.scheme | default .Values.prometheus.monitor.scheme }} + {{- end }} + {{- if or .Values.prometheus.monitor.metrics.tlsConfig .Values.prometheus.monitor.tlsConfig }} + tlsConfig: + {{- toYaml (.Values.prometheus.monitor.metrics.tlsConfig | default .Values.prometheus.monitor.tlsConfig) | nindent 8 }} + {{- end }} + {{- if or .Values.prometheus.monitor.metrics.bearerTokenFile .Values.prometheus.monitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.prometheus.monitor.metrics.bearerTokenFile | default .Values.prometheus.monitor.bearerTokenFile }} + {{- end }} + {{- with (.Values.prometheus.monitor.metrics.bearerTokenSecret | default .Values.prometheus.monitor.bearerTokenSecret) }} + bearerTokenSecret: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/stsdiscovery-role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/stsdiscovery-role.yaml new file mode 100644 index 0000000000..489de147c1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/stsdiscovery-role.yaml @@ -0,0 +1,26 @@ +{{- if and .Values.autosharding.enabled .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +rules: +- apiGroups: + - "" + resources: + - pods + verbs: + - get +- apiGroups: + - apps + resourceNames: + - {{ template "kube-state-metrics.fullname" . }} + resources: + - statefulsets + verbs: + - get + - list + - watch +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml new file mode 100644 index 0000000000..73b37a4f64 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.autosharding.enabled .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: stsdiscovery-{{ template "kube-state-metrics.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "kube-state-metrics.serviceAccountName" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml new file mode 100644 index 0000000000..f46305b517 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml @@ -0,0 +1,44 @@ +{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1") (.Values.verticalPodAutoscaler.enabled) }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: {{ template "kube-state-metrics.fullname" . }} + namespace: {{ template "kube-state-metrics.namespace" . }} + labels: + {{- include "kube-state-metrics.labels" . | indent 4 }} +spec: + {{- with .Values.verticalPodAutoscaler.recommenders }} + recommenders: + {{- toYaml . | nindent 4 }} + {{- end }} + resourcePolicy: + containerPolicies: + - containerName: {{ template "kube-state-metrics.name" . }} + {{- with .Values.verticalPodAutoscaler.controlledResources }} + controlledResources: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.verticalPodAutoscaler.controlledValues }} + controlledValues: {{ .Values.verticalPodAutoscaler.controlledValues }} + {{- end }} + {{- if .Values.verticalPodAutoscaler.maxAllowed }} + maxAllowed: + {{ toYaml .Values.verticalPodAutoscaler.maxAllowed | nindent 8 }} + {{- end }} + {{- if .Values.verticalPodAutoscaler.minAllowed }} + minAllowed: + {{ toYaml .Values.verticalPodAutoscaler.minAllowed | nindent 8 }} + {{- end }} + targetRef: + apiVersion: apps/v1 + {{- if .Values.autosharding.enabled }} + kind: StatefulSet + {{- else }} + kind: Deployment + {{- end }} + name: {{ template "kube-state-metrics.fullname" . }} + {{- with .Values.verticalPodAutoscaler.updatePolicy }} + updatePolicy: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/values.yaml new file mode 100644 index 0000000000..ab111f8091 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kube-state-metrics/values.yaml @@ -0,0 +1,523 @@ +# Default values for kube-state-metrics. +prometheusScrape: true +image: + registry: docker.io + repository: rancher/mirrored-kube-state-metrics-kube-state-metrics + tag: v2.12.0 + sha: "" + pullPolicy: IfNotPresent + +imagePullSecrets: [] +# - name: "image-pull-secret" + +global: + cattle: + systemDefaultRegistry: "" + + # To help compatibility with other charts which use global.imagePullSecrets. + # Allow either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style). + # global: + # imagePullSecrets: + # - name: pullSecret1 + # - name: pullSecret2 + # or + # global: + # imagePullSecrets: + # - pullSecret1 + # - pullSecret2 + imagePullSecrets: [] + # + # Allow parent charts to override registry hostname + imageRegistry: "" + +# If set to true, this will deploy kube-state-metrics as a StatefulSet and the data +# will be automatically sharded across <.Values.replicas> pods using the built-in +# autodiscovery feature: https://github.com/kubernetes/kube-state-metrics#automated-sharding +# This is an experimental feature and there are no stability guarantees. +autosharding: + enabled: false + +replicas: 1 + +# Change the deployment strategy when autosharding is disabled. +# ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy +# The default is "RollingUpdate" as per Kubernetes defaults. +# During a release, 'RollingUpdate' can lead to two running instances for a short period of time while 'Recreate' can create a small gap in data. +# updateStrategy: Recreate + +# Number of old history to retain to allow rollback +# Default Kubernetes value is set to 10 +revisionHistoryLimit: 10 + +# List of additional cli arguments to configure kube-state-metrics +# for example: --enable-gzip-encoding, --log-file, etc. +# all the possible args can be found here: https://github.com/kubernetes/kube-state-metrics/blob/master/docs/cli-arguments.md +extraArgs: [] + +# If false then the user will opt out of automounting API credentials. +automountServiceAccountToken: true + +service: + port: 8080 + # Default to clusterIP for backward compatibility + type: ClusterIP + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + nodePort: 0 + loadBalancerIP: "" + # Only allow access to the loadBalancerIP from these IPs + loadBalancerSourceRanges: [] + clusterIP: "" + annotations: {} + +## Additional labels to add to all resources +customLabels: {} + # app: kube-state-metrics + +## Override selector labels +selectorOverride: {} + +## set to true to add the release label so scraping of the servicemonitor with kube-prometheus-stack works out of the box +releaseLabel: false + +hostNetwork: false + +rbac: + # If true, create & use RBAC resources + create: true + + # Set to a rolename to use existing role - skipping role creating - but still doing serviceaccount and rolebinding to it, rolename set here. + # useExistingRole: your-existing-role + + # If set to false - Run without Cluteradmin privs needed - ONLY works if namespace is also set (if useExistingRole is set this name is used as ClusterRole or Role to bind to) + useClusterRole: true + + # Add permissions for CustomResources' apiGroups in Role/ClusterRole. Should be used in conjunction with Custom Resource State Metrics configuration + # Example: + # - apiGroups: ["monitoring.coreos.com"] + # resources: ["prometheuses"] + # verbs: ["list", "watch"] + extraRules: [] + +# Configure kube-rbac-proxy. When enabled, creates one kube-rbac-proxy container per exposed HTTP endpoint (metrics and telemetry if enabled). +# The requests are served through the same service but requests are then HTTPS. +kubeRBACProxy: + enabled: false + image: + repository: rancher/mirrored-brancz-kube-rbac-proxy + tag: v0.18.0 + sha: "" + pullPolicy: IfNotPresent + + # List of additional cli arguments to configure kube-rbac-prxy + # for example: --tls-cipher-suites, --log-file, etc. + # all the possible args can be found here: https://github.com/brancz/kube-rbac-proxy#usage + extraArgs: [] + + ## Specify security settings for a Container + ## Allows overrides and additional options compared to (Pod) securityContext + ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + containerSecurityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 64Mi + # requests: + # cpu: 10m + # memory: 32Mi + + ## volumeMounts enables mounting custom volumes in rbac-proxy containers + ## Useful for TLS certificates and keys + volumeMounts: [] + # - mountPath: /etc/tls + # name: kube-rbac-proxy-tls + # readOnly: true + +serviceAccount: + # Specifies whether a ServiceAccount should be created, require rbac true + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + name: + # Reference to one or more secrets to be used when pulling images + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + imagePullSecrets: [] + # ServiceAccount annotations. + # Use case: AWS EKS IAM roles for service accounts + # ref: https://docs.aws.amazon.com/eks/latest/userguide/specify-service-account-role.html + annotations: {} + # If false then the user will opt out of automounting API credentials. + automountServiceAccountToken: true + +prometheus: + monitor: + enabled: false + annotations: {} + additionalLabels: {} + namespace: "" + namespaceSelector: [] + jobLabel: "" + targetLabels: [] + podTargetLabels: [] + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + selectorOverride: {} + + ## kube-state-metrics endpoint + http: + interval: "" + scrapeTimeout: "" + proxyUrl: "" + ## Whether to enable HTTP2 for servicemonitor + enableHttp2: false + honorLabels: false + metricRelabelings: [] + relabelings: [] + scheme: "" + ## File to read bearer token for scraping targets + bearerTokenFile: "" + ## Secret to mount to read bearer token for scraping targets. The secret needs + ## to be in the same namespace as the service monitor and accessible by the + ## Prometheus Operator + bearerTokenSecret: {} + # name: secret-name + # key: key-name + tlsConfig: {} + + ## selfMonitor endpoint + metrics: + interval: "" + scrapeTimeout: "" + proxyUrl: "" + ## Whether to enable HTTP2 for servicemonitor + enableHttp2: false + honorLabels: false + metricRelabelings: [] + relabelings: [] + scheme: "" + ## File to read bearer token for scraping targets + bearerTokenFile: "" + ## Secret to mount to read bearer token for scraping targets. The secret needs + ## to be in the same namespace as the service monitor and accessible by the + ## Prometheus Operator + bearerTokenSecret: {} + # name: secret-name + # key: key-name + tlsConfig: {} + +## Specify if a Pod Security Policy for kube-state-metrics must be created +## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ +## +podSecurityPolicy: + enabled: false + annotations: {} + ## Specify pod annotations + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#apparmor + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp + ## Ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/#sysctl + ## + # seccomp.security.alpha.kubernetes.io/allowedProfileNames: '*' + # seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default' + # apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default' + + additionalVolumes: [] + +## Configure network policy for kube-state-metrics +networkPolicy: + enabled: false + # networkPolicy.flavor -- Flavor of the network policy to use. + # Can be: + # * kubernetes for networking.k8s.io/v1/NetworkPolicy + # * cilium for cilium.io/v2/CiliumNetworkPolicy + flavor: kubernetes + + ## Configure the cilium network policy kube-apiserver selector + # cilium: + # kubeApiServerSelector: + # - toEntities: + # - kube-apiserver + + # egress: + # - {} + # ingress: + # - {} + # podSelector: + # matchLabels: + # app.kubernetes.io/name: kube-state-metrics + +securityContext: + enabled: true + runAsGroup: 65534 + runAsUser: 65534 + fsGroup: 65534 + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + +## Specify security settings for a Container +## Allows overrides and additional options compared to (Pod) securityContext +## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container +containerSecurityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + +## Node labels for pod assignment +## Ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +## Affinity settings for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ +affinity: {} + +## Tolerations for pod assignment +## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +tolerations: [] + +## Topology spread constraints for pod assignment +## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ +topologySpreadConstraints: [] + +# Annotations to be added to the deployment/statefulset +annotations: {} + +# Annotations to be added to the pod +podAnnotations: {} + +## Assign a PriorityClassName to pods if set +# priorityClassName: "" + +# Ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ +podDisruptionBudget: {} + +# Comma-separated list of metrics to be exposed. +# This list comprises of exact metric names and/or regex patterns. +# The allowlist and denylist are mutually exclusive. +metricAllowlist: [] + +# Comma-separated list of metrics not to be enabled. +# This list comprises of exact metric names and/or regex patterns. +# The allowlist and denylist are mutually exclusive. +metricDenylist: [] + +# Comma-separated list of additional Kubernetes label keys that will be used in the resource's +# labels metric. By default the metric contains only name and namespace labels. +# To include additional labels, provide a list of resource names in their plural form and Kubernetes +# label keys you would like to allow for them (Example: '=namespaces=[k8s-label-1,k8s-label-n,...],pods=[app],...)'. +# A single '*' can be provided per resource instead to allow any labels, but that has +# severe performance implications (Example: '=pods=[*]'). +metricLabelsAllowlist: [] + # - namespaces=[k8s-label-1,k8s-label-n] + +# Comma-separated list of Kubernetes annotations keys that will be used in the resource' +# labels metric. By default the metric contains only name and namespace labels. +# To include additional annotations provide a list of resource names in their plural form and Kubernetes +# annotation keys you would like to allow for them (Example: '=namespaces=[kubernetes.io/team,...],pods=[kubernetes.io/team],...)'. +# A single '*' can be provided per resource instead to allow any annotations, but that has +# severe performance implications (Example: '=pods=[*]'). +metricAnnotationsAllowList: [] + # - pods=[k8s-annotation-1,k8s-annotation-n] + +# Available collectors for kube-state-metrics. +# By default, all available resources are enabled, comment out to disable. +collectors: + - certificatesigningrequests + - configmaps + - cronjobs + - daemonsets + - deployments + - endpoints + - horizontalpodautoscalers + - ingresses + - jobs + - leases + - limitranges + - mutatingwebhookconfigurations + - namespaces + - networkpolicies + - nodes + - persistentvolumeclaims + - persistentvolumes + - poddisruptionbudgets + - pods + - replicasets + - replicationcontrollers + - resourcequotas + - secrets + - services + - statefulsets + - storageclasses + - validatingwebhookconfigurations + - volumeattachments + +# Enabling kubeconfig will pass the --kubeconfig argument to the container +kubeconfig: + enabled: false + # base64 encoded kube-config file + secret: + +# Enabling support for customResourceState, will create a configMap including your config that will be read from kube-state-metrics +customResourceState: + enabled: false + # Add (Cluster)Role permissions to list/watch the customResources defined in the config to rbac.extraRules + config: {} + +# Enable only the release namespace for collecting resources. By default all namespaces are collected. +# If releaseNamespace and namespaces are both set a merged list will be collected. +releaseNamespace: false + +# Comma-separated list(string) or yaml list of namespaces to be enabled for collecting resources. By default all namespaces are collected. +namespaces: "" + +# Comma-separated list of namespaces not to be enabled. If namespaces and namespaces-denylist are both set, +# only namespaces that are excluded in namespaces-denylist will be used. +namespacesDenylist: "" + +## Override the deployment namespace +## +namespaceOverride: "" + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 64Mi + # requests: + # cpu: 10m + # memory: 32Mi + +## Provide a k8s version to define apiGroups for podSecurityPolicy Cluster Role. +## For example: kubeTargetVersionOverride: 1.14.9 +## +kubeTargetVersionOverride: "" + +# Enable self metrics configuration for service and Service Monitor +# Default values for telemetry configuration can be overridden +# If you set telemetryNodePort, you must also set service.type to NodePort +selfMonitor: + enabled: false + # telemetryHost: 0.0.0.0 + # telemetryPort: 8081 + # telemetryNodePort: 0 + +# Enable vertical pod autoscaler support for kube-state-metrics +verticalPodAutoscaler: + enabled: false + + # Recommender responsible for generating recommendation for the object. + # List should be empty (then the default recommender will generate the recommendation) + # or contain exactly one recommender. + # recommenders: [] + # - name: custom-recommender-performance + + # List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory + controlledResources: [] + # Specifies which resource values should be controlled: RequestsOnly or RequestsAndLimits. + # controlledValues: RequestsAndLimits + + # Define the max allowed resources for the pod + maxAllowed: {} + # cpu: 200m + # memory: 100Mi + # Define the min allowed resources for the pod + minAllowed: {} + # cpu: 200m + # memory: 100Mi + + # updatePolicy: + # Specifies minimal number of replicas which need to be alive for VPA Updater to attempt pod eviction + # minReplicas: 1 + # Specifies whether recommended updates are applied when a Pod is started and whether recommended updates + # are applied during the life of a Pod. Possible values are "Off", "Initial", "Recreate", and "Auto". + # updateMode: Auto + +# volumeMounts are used to add custom volume mounts to deployment. +# See example below +volumeMounts: [] +# - mountPath: /etc/config +# name: config-volume + +# volumes are used to add custom volumes to deployment +# See example below +volumes: [] +# - configMap: +# name: cm-for-volume +# name: config-volume + +# Extra manifests to deploy as an array +extraManifests: [] + # - apiVersion: v1 + # kind: ConfigMap + # metadata: + # labels: + # name: prometheus-extra + # data: + # extra-data: "value" + +## Containers allows injecting additional containers. +containers: [] + # - name: crd-init + # image: kiwigrid/k8s-sidecar:latest + +## InitContainers allows injecting additional initContainers. +initContainers: [] + # - name: crd-sidecar + # image: kiwigrid/k8s-sidecar:latest + +## Liveness probe +## +livenessProbe: + failureThreshold: 3 + httpGet: + httpHeaders: [] + scheme: http + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + +## Readiness probe +## +readinessProbe: + failureThreshold: 3 + httpGet: + httpHeaders: [] + scheme: http + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/.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/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/Chart.yaml new file mode 100644 index 0000000000..90e7160519 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: kubeAdmControllerManager +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmControllerManager/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/.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/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/Chart.yaml new file mode 100644 index 0000000000..7e2bc0fe7c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: kubeAdmEtcd +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmEtcd/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/.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/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/Chart.yaml new file mode 100644 index 0000000000..7fc724e9e8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: kubeAdmProxy +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmProxy/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/.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/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/Chart.yaml new file mode 100644 index 0000000000..502a39085f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: kubeAdmScheduler +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/kubeAdmScheduler/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/.helmignore new file mode 100644 index 0000000000..f0c1319444 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/.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/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/Chart.yaml new file mode 100644 index 0000000000..bed274d82c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/Chart.yaml @@ -0,0 +1,27 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-prometheus-adapter +apiVersion: v1 +appVersion: v0.11.2 +description: A Helm chart for k8s prometheus adapter +home: https://github.com/kubernetes-sigs/prometheus-adapter +keywords: +- hpa +- metrics +- prometheus +- adapter +maintainers: +- email: mattias.gees@jetstack.io + name: mattiasgees +- name: steven-sheehy +- email: hfernandez@mesosphere.com + name: hectorj2f +name: prometheus-adapter +sources: +- https://github.com/kubernetes/charts +- https://github.com/kubernetes-sigs/prometheus-adapter +version: 4.10.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/README.md new file mode 100644 index 0000000000..d77bb0c920 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/README.md @@ -0,0 +1,160 @@ +# Prometheus Adapter + +Installs the [Prometheus Adapter](https://github.com/kubernetes-sigs/prometheus-adapter) for the Custom Metrics API. Custom metrics are used in Kubernetes by [Horizontal Pod Autoscalers](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) to scale workloads based upon your own metric pulled from an external metrics provider like Prometheus. This chart complements the [metrics-server](https://github.com/helm/charts/tree/master/stable/metrics-server) chart that provides resource only metrics. + +## Prerequisites + +Kubernetes 1.14+ + +## Get Helm Repositories Info + +```console +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update +``` + +_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Helm Chart + +```console +helm install [RELEASE_NAME] prometheus-community/prometheus-adapter +``` + +_See [configuration](#configuration) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Uninstall Helm Chart + +```console +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +## Upgrading Helm Chart + +```console +helm upgrade [RELEASE_NAME] [CHART] --install +``` + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### To 4.2.0 + +Readiness and liveness probes are now fully configurable through values `readinessProbe` and `livenessProbe`. The previous values have been kept as defaults. + +### To 4.0.0 + +Previously, security context of the container was set directly in the deployment template. This release makes it configurable through the new configuration variable `securityContext` whilst keeping the previously set values as defaults. Furthermore, previous variable `runAsUser` is now set in `securityContext` and is not used any longer. Please, use `securityContext.runAsUser` instead. In the same security context, `seccompProfile` has been enabled and set to type `RuntimeDefault`. + +### To 3.0.0 + +Due to a change in deployment labels, the upgrade requires `helm upgrade --force` in order to re-create the deployment. + +## 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, visit the chart's [values.yaml](./values.yaml), or run these configuration commands: + +```console +helm show values prometheus-community/prometheus-adapter +``` + +### Prometheus Service Endpoint + +To use the chart, ensure the `prometheus.url` and `prometheus.port` are configured with the correct Prometheus service endpoint. If Prometheus is exposed under HTTPS the host's CA Bundle must be exposed to the container using `extraVolumes` and `extraVolumeMounts`. + +### Adapter Rules + +Additionally, the chart comes with a set of default rules out of the box but they may pull in too many metrics or not map them correctly for your needs. Therefore, it is recommended to populate `rules.custom` with a list of rules (see the [config document](https://github.com/kubernetes-sigs/prometheus-adapter/blob/master/docs/config.md) for the proper format). + +### Horizontal Pod Autoscaler Metrics + +Finally, to configure your Horizontal Pod Autoscaler to use the custom metric, see the custom metrics section of the [HPA walkthrough](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics). + +The Prometheus Adapter can serve three different [metrics APIs](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-metrics-apis): + +### Custom Metrics + +Enabling this option will cause custom metrics to be served at `/apis/custom.metrics.k8s.io/v1beta1`. Enabled by default when `rules.default` is true, but can be customized by populating `rules.custom`: + +```yaml +rules: + custom: + - seriesQuery: '{__name__=~"^some_metric_count$"}' + resources: + template: <<.Resource>> + name: + matches: "" + as: "my_custom_metric" + metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>) +``` + +### External Metrics + +Enabling this option will cause external metrics to be served at `/apis/external.metrics.k8s.io/v1beta1`. Can be enabled by populating `rules.external`: + +```yaml +rules: + external: + - seriesQuery: '{__name__=~"^some_metric_count$"}' + resources: + template: <<.Resource>> + name: + matches: "" + as: "my_external_metric" + metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>) +``` + +### Resource Metrics + +Enabling this option will cause resource metrics to be served at `/apis/metrics.k8s.io/v1beta1`. Resource metrics will allow pod CPU and Memory metrics to be used in [Horizontal Pod Autoscalers](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) as well as the `kubectl top` command. Can be enabled by populating `rules.resource`: + +```yaml +rules: + resource: + cpu: + containerQuery: | + sum by (<<.GroupBy>>) ( + rate(container_cpu_usage_seconds_total{container!="",<<.LabelMatchers>>}[3m]) + ) + nodeQuery: | + sum by (<<.GroupBy>>) ( + rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal",<<.LabelMatchers>>}[3m]) + ) + resources: + overrides: + node: + resource: node + namespace: + resource: namespace + pod: + resource: pod + containerLabel: container + memory: + containerQuery: | + sum by (<<.GroupBy>>) ( + avg_over_time(container_memory_working_set_bytes{container!="",<<.LabelMatchers>>}[3m]) + ) + nodeQuery: | + sum by (<<.GroupBy>>) ( + avg_over_time(node_memory_MemTotal_bytes{<<.LabelMatchers>>}[3m]) + - + avg_over_time(node_memory_MemAvailable_bytes{<<.LabelMatchers>>}[3m]) + ) + resources: + overrides: + node: + resource: node + namespace: + resource: namespace + pod: + resource: pod + containerLabel: container + window: 3m +``` + +**NOTE:** Setting a value for `rules.resource` will also deploy the resource metrics API service, providing the same functionality as [metrics-server](https://github.com/helm/charts/tree/master/stable/metrics-server). As such it is not possible to deploy them both in the same cluster. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/NOTES.txt b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/NOTES.txt new file mode 100644 index 0000000000..b7b9b99322 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/NOTES.txt @@ -0,0 +1,9 @@ +{{ template "k8s-prometheus-adapter.fullname" . }} has been deployed. +In a few minutes you should be able to list metrics using the following command(s): +{{ if .Values.rules.resource }} + kubectl get --raw /apis/metrics.k8s.io/v1beta1 +{{- end }} + kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1 +{{ if .Values.rules.external }} + kubectl get --raw /apis/external.metrics.k8s.io/v1beta1 +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/_helpers.tpl new file mode 100644 index 0000000000..edbb829b2b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/_helpers.tpl @@ -0,0 +1,113 @@ +# Rancher +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "k8s-prometheus-adapter.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 "k8s-prometheus-adapter.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 -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "k8s-prometheus-adapter.namespace" -}} +{{- default .Release.Namespace .Values.namespaceOverride -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "k8s-prometheus-adapter.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Generate basic labels +*/}} +{{- define "k8s-prometheus-adapter.labels" }} +helm.sh/chart: {{ include "k8s-prometheus-adapter.chart" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: metrics +app.kubernetes.io/part-of: {{ template "k8s-prometheus-adapter.name" . }} +{{- include "k8s-prometheus-adapter.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- if .Values.customLabels }} +{{ toYaml .Values.customLabels }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "k8s-prometheus-adapter.selectorLabels" }} +app.kubernetes.io/name: {{ include "k8s-prometheus-adapter.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "k8s-prometheus-adapter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "k8s-prometheus-adapter.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* Get Policy API Version */}} +{{- define "k8s-prometheus-adapter.pdb.apiVersion" -}} +{{- if and (.Capabilities.APIVersions.Has "policy/v1") (semverCompare ">= 1.21-0" .Capabilities.KubeVersion.Version) -}} + {{- print "policy/v1" -}} +{{- else -}} + {{- print "policy/v1beta1" -}} +{{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/certmanager.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/certmanager.yaml new file mode 100644 index 0000000000..4e32c964c6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/certmanager.yaml @@ -0,0 +1,76 @@ +{{- if .Values.certManager.enabled -}} +--- +# Create a selfsigned Issuer, in order to create a root CA certificate for +# signing webhook serving certificates +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ template "k8s-prometheus-adapter.fullname" . }}-self-signed-issuer + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} +spec: + selfSigned: {} +--- +# Generate a CA Certificate used to sign certificates for the webhook +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "k8s-prometheus-adapter.fullname" . }}-root-cert + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} +spec: + secretName: {{ template "k8s-prometheus-adapter.fullname" . }}-root-cert + duration: {{ .Values.certManager.caCertDuration }} + issuerRef: + name: {{ template "k8s-prometheus-adapter.fullname" . }}-self-signed-issuer + commonName: "ca.webhook.prometheus-adapter" + isCA: true +--- +# Create an Issuer that uses the above generated CA certificate to issue certs +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ template "k8s-prometheus-adapter.fullname" . }}-root-issuer + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} +spec: + ca: + secretName: {{ template "k8s-prometheus-adapter.fullname" . }}-root-cert +--- +# Finally, generate a serving certificate for the apiservices to use +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "k8s-prometheus-adapter.fullname" . }}-cert + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} +spec: + secretName: {{ template "k8s-prometheus-adapter.fullname" . }} + duration: {{ .Values.certManager.certDuration }} + issuerRef: + name: {{ template "k8s-prometheus-adapter.fullname" . }}-root-issuer + dnsNames: + - {{ template "k8s-prometheus-adapter.fullname" . }} + - {{ template "k8s-prometheus-adapter.fullname" . }}.{{ include "k8s-prometheus-adapter.namespace" . }} + - {{ template "k8s-prometheus-adapter.fullname" . }}.{{ include "k8s-prometheus-adapter.namespace" . }}.svc +{{- end -}} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-auth-delegator.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-auth-delegator.yaml new file mode 100644 index 0000000000..6701e6ba08 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-auth-delegator.yaml @@ -0,0 +1,20 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-system-auth-delegator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: +- kind: ServiceAccount + name: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-auth-reader.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-auth-reader.yaml new file mode 100644 index 0000000000..fe13048847 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-auth-reader.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.rbac.create .Values.rbac.useAuthReaderClusterRole -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-auth-reader +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: extension-apiserver-authentication-reader +subjects: +- kind: ServiceAccount + name: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-resource-reader.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-resource-reader.yaml new file mode 100644 index 0000000000..67efd2aa2f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-binding-resource-reader.yaml @@ -0,0 +1,20 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-resource-reader +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "k8s-prometheus-adapter.name" . }}-resource-reader +subjects: +- kind: ServiceAccount + name: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-resource-reader.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-resource-reader.yaml new file mode 100644 index 0000000000..2c690a03cc --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/cluster-role-resource-reader.yaml @@ -0,0 +1,24 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-resource-reader +rules: +- apiGroups: + - "" + resources: + - namespaces + - pods + - services + - configmaps + verbs: + - get + - list + - watch +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/configmap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/configmap.yaml new file mode 100644 index 0000000000..17f415d970 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/configmap.yaml @@ -0,0 +1,97 @@ +{{- if not .Values.rules.existing -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "k8s-prometheus-adapter.fullname" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} +data: + config.yaml: | +{{- if or .Values.rules.default .Values.rules.custom }} + rules: +{{- if .Values.rules.default }} + - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}' + seriesFilters: [] + resources: + overrides: + namespace: + resource: namespace + pod: + resource: pod + name: + matches: ^container_(.*)_seconds_total$ + as: "" + metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[5m])) + by (<<.GroupBy>>) + - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}' + seriesFilters: + - isNot: ^container_.*_seconds_total$ + resources: + overrides: + namespace: + resource: namespace + pod: + resource: pod + name: + matches: ^container_(.*)_total$ + as: "" + metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>,container!="POD"}[5m])) + by (<<.GroupBy>>) + - seriesQuery: '{__name__=~"^container_.*",container!="POD",namespace!="",pod!=""}' + seriesFilters: + - isNot: ^container_.*_total$ + resources: + overrides: + namespace: + resource: namespace + pod: + resource: pod + name: + matches: ^container_(.*)$ + as: "" + metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>,container!="POD"}) by (<<.GroupBy>>) + - seriesQuery: '{namespace!="",__name__!~"^container_.*"}' + seriesFilters: + - isNot: .*_total$ + resources: + template: <<.Resource>> + name: + matches: "" + as: "" + metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>) + - seriesQuery: '{namespace!="",__name__!~"^container_.*"}' + seriesFilters: + - isNot: .*_seconds_total + resources: + template: <<.Resource>> + name: + matches: ^(.*)_total$ + as: "" + metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[5m])) by (<<.GroupBy>>) + - seriesQuery: '{namespace!="",__name__!~"^container_.*"}' + seriesFilters: [] + resources: + template: <<.Resource>> + name: + matches: ^(.*)_seconds_total$ + as: "" + metricsQuery: sum(rate(<<.Series>>{<<.LabelMatchers>>}[5m])) by (<<.GroupBy>>) +{{- end -}} +{{- if .Values.rules.custom }} +{{ toYaml .Values.rules.custom | indent 4 }} +{{- end -}} +{{- end -}} +{{- if .Values.rules.external }} + externalRules: +{{ toYaml .Values.rules.external | indent 4 }} +{{- end -}} +{{- if .Values.rules.resource }} + resourceRules: +{{ toYaml .Values.rules.resource | indent 6 }} +{{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-apiservice.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-apiservice.yaml new file mode 100644 index 0000000000..8b7b4e555e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-apiservice.yaml @@ -0,0 +1,34 @@ +{{- if or .Values.rules.default .Values.rules.custom }} +{{- if .Capabilities.APIVersions.Has "apiregistration.k8s.io/v1" }} +apiVersion: apiregistration.k8s.io/v1 +{{- else }} +apiVersion: apiregistration.k8s.io/v1beta1 +{{- end }} +kind: APIService +metadata: +{{- if or .Values.certManager.enabled .Values.customAnnotations }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-root-cert" (include "k8s-prometheus-adapter.namespace" .) (include "k8s-prometheus-adapter.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-root-cert" (include "k8s-prometheus-adapter.namespace" .) (include "k8s-prometheus-adapter.fullname" .) | quote }} + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} +{{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: v1beta1.custom.metrics.k8s.io +spec: + service: + name: {{ template "k8s-prometheus-adapter.fullname" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} + {{- if .Values.tls.enable }} + caBundle: {{ b64enc .Values.tls.ca }} + {{- end }} + group: custom.metrics.k8s.io + version: v1beta1 + {{- if not (or .Values.tls.enable .Values.certManager.enabled) }} + insecureSkipTLSVerify: true + {{- end }} + groupPriorityMinimum: 100 + versionPriority: 100 +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-cluster-role-binding-hpa.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-cluster-role-binding-hpa.yaml new file mode 100644 index 0000000000..0cc6920836 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-cluster-role-binding-hpa.yaml @@ -0,0 +1,24 @@ +{{- /* +This if must be aligned with custom-metrics-cluster-role.yaml +as otherwise this binding will point to not existing role. +*/ -}} +{{- if and .Values.rbac.create (or .Values.rules.default .Values.rules.custom) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-hpa-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "k8s-prometheus-adapter.name" . }}-server-resources +subjects: +- kind: ServiceAccount + name: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-cluster-role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-cluster-role.yaml new file mode 100644 index 0000000000..f441e1bdb6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/custom-metrics-cluster-role.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.rbac.create (or .Values.rules.default .Values.rules.custom) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-server-resources +rules: +- apiGroups: + - custom.metrics.k8s.io + resources: {{ toYaml .Values.rbac.customMetrics.resources | nindent 2 }} + verbs: ["*"] +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/deployment.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/deployment.yaml new file mode 100644 index 0000000000..03267b5e3b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/deployment.yaml @@ -0,0 +1,151 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + {{- if or .Values.customAnnotations .Values.deploymentAnnotations }} + annotations: + {{- with .Values.customAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.deploymentAnnotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.fullname" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} +spec: + replicas: {{ .Values.replicas }} + strategy: {{ toYaml .Values.strategy | nindent 4 }} + selector: + matchLabels: + {{- include "k8s-prometheus-adapter.selectorLabels" . | indent 6 }} + template: + metadata: + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | trim | nindent 8 }} + {{- end }} + name: {{ template "k8s-prometheus-adapter.name" . }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.customAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + {{- if .Values.hostNetwork.enabled }} + hostNetwork: true + {{- end }} + {{- if .Values.dnsPolicy }} + dnsPolicy: {{ .Values.dnsPolicy }} + {{- end}} + {{- with .Values.dnsConfig }} + dnsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ template "system_default_registry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- with .Values.env }} + env: + {{- toYaml . | nindent 8 }} + {{- end }} + args: + - /adapter + - --secure-port={{ .Values.listenPort }} + {{- if or .Values.tls.enable .Values.certManager.enabled }} + - --tls-cert-file=/var/run/serving-cert/tls.crt + - --tls-private-key-file=/var/run/serving-cert/tls.key + {{- end }} + - --cert-dir=/tmp/cert + - --prometheus-url={{ tpl .Values.prometheus.url . }}{{ if .Values.prometheus.port }}:{{ .Values.prometheus.port }}{{end}}{{ .Values.prometheus.path }} + - --metrics-relist-interval={{ .Values.metricsRelistInterval }} + - --v={{ .Values.logLevel }} + - --config=/etc/adapter/config.yaml + {{- if .Values.extraArguments }} + {{- toYaml .Values.extraArguments | trim | nindent 8 }} + {{- end }} + ports: + - containerPort: {{ .Values.listenPort }} + name: https + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- with .Values.startupProbe }} + startupProbe: + {{- toYaml . | nindent 10 }} + {{- end }} + {{- if .Values.resources }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + {{- end }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 10 }} + {{- end }} + volumeMounts: + {{- if .Values.extraVolumeMounts }} + {{ toYaml .Values.extraVolumeMounts | trim | nindent 8 }} + {{ end }} + - mountPath: /etc/adapter/ + name: config + readOnly: true + - mountPath: /tmp + name: tmp + {{- if or .Values.tls.enable .Values.certManager.enabled }} + - mountPath: /var/run/serving-cert + name: volume-serving-cert + readOnly: true + {{- end }} + {{- with .Values.extraContainers }} + {{- toYaml . | nindent 6 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} + nodeSelector: + {{- toYaml .Values.nodeSelector | nindent 8 }} + affinity: + {{- toYaml .Values.affinity | nindent 8 }} + topologySpreadConstraints: + {{- toYaml .Values.topologySpreadConstraints | nindent 8 }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.tolerations }} +{{- toYaml .Values.tolerations | nindent 8 }} +{{- end }} + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- range .Values.image.pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + volumes: + {{- if .Values.extraVolumes }} + {{ toYaml .Values.extraVolumes | trim | nindent 6 }} + {{ end }} + - name: config + configMap: + name: {{ .Values.rules.existing | default (include "k8s-prometheus-adapter.fullname" . ) }} + - name: tmp + emptyDir: {} + {{- if or .Values.tls.enable .Values.certManager.enabled }} + - name: volume-serving-cert + secret: + secretName: {{ template "k8s-prometheus-adapter.fullname" . }} + {{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-apiservice.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-apiservice.yaml new file mode 100644 index 0000000000..21339af128 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-apiservice.yaml @@ -0,0 +1,34 @@ +{{- if .Values.rules.external }} +{{- if .Capabilities.APIVersions.Has "apiregistration.k8s.io/v1" }} +apiVersion: apiregistration.k8s.io/v1 +{{- else }} +apiVersion: apiregistration.k8s.io/v1beta1 +{{- end }} +kind: APIService +metadata: +{{- if or .Values.certManager.enabled .Values.customAnnotations }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-root-cert" (include "k8s-prometheus-adapter.namespace" .) (include "k8s-prometheus-adapter.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-root-cert" (include "k8s-prometheus-adapter.namespace" .) (include "k8s-prometheus-adapter.fullname" .) | quote }} + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} +{{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: v1beta1.external.metrics.k8s.io +spec: + service: + name: {{ template "k8s-prometheus-adapter.fullname" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} + {{- if .Values.tls.enable }} + caBundle: {{ b64enc .Values.tls.ca }} + {{- end }} + group: external.metrics.k8s.io + version: v1beta1 + {{- if not (or .Values.tls.enable .Values.certManager.enabled) }} + insecureSkipTLSVerify: true + {{- end }} + groupPriorityMinimum: 100 + versionPriority: 100 +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-cluster-role-binding-hpa.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-cluster-role-binding-hpa.yaml new file mode 100644 index 0000000000..05547bd323 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-cluster-role-binding-hpa.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.rbac.create .Values.rules.external -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-hpa-controller-external-metrics +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "k8s-prometheus-adapter.name" . }}-external-metrics +subjects: +- kind: ServiceAccount + name: horizontal-pod-autoscaler + namespace: kube-system +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-cluster-role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-cluster-role.yaml new file mode 100644 index 0000000000..71783fd4b2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/external-metrics-cluster-role.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.rbac.create .Values.rules.external -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-external-metrics +rules: +- apiGroups: + - "external.metrics.k8s.io" + resources: {{ toYaml .Values.rbac.externalMetrics.resources | nindent 2 }} + verbs: + - list + - get + - watch +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/pdb.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/pdb.yaml new file mode 100644 index 0000000000..205761a9f1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/pdb.yaml @@ -0,0 +1,23 @@ +{{- if .Values.podDisruptionBudget.enabled }} +apiVersion: {{ include "k8s-prometheus-adapter.pdb.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ template "k8s-prometheus-adapter.fullname" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} +spec: + {{- if .Values.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- include "k8s-prometheus-adapter.selectorLabels" . | indent 6 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/psp.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/psp.yaml new file mode 100644 index 0000000000..ec26af502c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/psp.yaml @@ -0,0 +1,66 @@ +{{- if and .Values.psp.create (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +--- +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "k8s-prometheus-adapter.fullname" . }} + {{- with (merge .Values.customAnnotations .Values.psp.annotations) }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} +spec: + {{- if .Values.hostNetwork.enabled }} + hostNetwork: true + hostPorts: + - min: {{ .Values.listenPort }} + max: {{ .Values.listenPort }} + {{- end }} + fsGroup: + rule: RunAsAny + runAsGroup: + rule: RunAsAny + runAsUser: + rule: MustRunAs + ranges: + - min: 1024 + max: 65535 + seLinux: + rule: RunAsAny + supplementalGroups: + rule: RunAsAny + volumes: + - secret + - emptyDir + - configMap +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-psp +rules: +- apiGroups: + - 'policy' + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "k8s-prometheus-adapter.fullname" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-psp +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "k8s-prometheus-adapter.name" . }}-psp +subjects: +- kind: ServiceAccount + name: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-apiservice.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-apiservice.yaml new file mode 100644 index 0000000000..0cc9fff6a2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-apiservice.yaml @@ -0,0 +1,34 @@ +{{- if .Values.rules.resource}} +{{- if .Capabilities.APIVersions.Has "apiregistration.k8s.io/v1" }} +apiVersion: apiregistration.k8s.io/v1 +{{- else }} +apiVersion: apiregistration.k8s.io/v1beta1 +{{- end }} +kind: APIService +metadata: +{{- if or .Values.certManager.enabled .Values.customAnnotations }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-root-cert" (include "k8s-prometheus-adapter.namespace" .) (include "k8s-prometheus-adapter.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-root-cert" (include "k8s-prometheus-adapter.namespace" .) (include "k8s-prometheus-adapter.fullname" .) | quote }} + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} +{{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: v1beta1.metrics.k8s.io +spec: + service: + name: {{ template "k8s-prometheus-adapter.fullname" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} + {{- if .Values.tls.enable }} + caBundle: {{ b64enc .Values.tls.ca }} + {{- end }} + group: metrics.k8s.io + version: v1beta1 + {{- if not (or .Values.tls.enable .Values.certManager.enabled) }} + insecureSkipTLSVerify: true + {{- end }} + groupPriorityMinimum: 100 + versionPriority: 100 +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-cluster-role-binding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-cluster-role-binding.yaml new file mode 100644 index 0000000000..3c247e48d2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-cluster-role-binding.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.rbac.create .Values.rules.resource -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-hpa-controller-metrics +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "k8s-prometheus-adapter.name" . }}-metrics +subjects: +- kind: ServiceAccount + name: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-cluster-role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-cluster-role.yaml new file mode 100644 index 0000000000..73d8953046 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/resource-metrics-cluster-role.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.rbac.create .Values.rules.resource -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-metrics +rules: +- apiGroups: + - "" + resources: + - pods + - nodes + - nodes/stats + verbs: + - get + - list + - watch +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/role-binding-auth-reader.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/role-binding-auth-reader.yaml new file mode 100644 index 0000000000..f01997e62d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/role-binding-auth-reader.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.rbac.create (not .Values.rbac.useAuthReaderClusterRole) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.name" . }}-auth-reader + namespace: kube-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: extension-apiserver-authentication-reader +subjects: +- kind: ServiceAccount + name: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . | quote }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/secret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/secret.yaml new file mode 100644 index 0000000000..3e7e8887bd --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/secret.yaml @@ -0,0 +1,17 @@ +{{- if .Values.tls.enable -}} +apiVersion: v1 +kind: Secret +metadata: + {{- if .Values.customAnnotations }} + annotations: + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.fullname" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} +type: kubernetes.io/tls +data: + tls.crt: {{ b64enc .Values.tls.certificate }} + tls.key: {{ b64enc .Values.tls.key }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/service.yaml new file mode 100644 index 0000000000..4879385ebc --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/service.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + {{- if or .Values.service.annotations .Values.customAnnotations }} + annotations: + {{- if .Values.service.annotations }} + {{ toYaml .Values.service.annotations | indent 4 }} + {{- end }} + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} + {{- end }} + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.fullname" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} +spec: +{{- if .Values.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.service.ipDualStack.ipFamilyPolicy }} +{{- end }} + ports: + - port: {{ .Values.service.port }} + name: https + protocol: TCP + targetPort: https + selector: + {{- include "k8s-prometheus-adapter.selectorLabels" . | indent 4 }} + type: {{ .Values.service.type }} + {{- if .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/serviceaccount.yaml new file mode 100644 index 0000000000..30a169ae0e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + {{- include "k8s-prometheus-adapter.labels" . | indent 4 }} + name: {{ template "k8s-prometheus-adapter.serviceAccountName" . }} + namespace: {{ include "k8s-prometheus-adapter.namespace" . }} +{{- if or .Values.serviceAccount.annotations .Values.customAnnotations }} + annotations: + {{- if .Values.serviceAccount.annotations }} + {{- toYaml .Values.serviceAccount.annotations | nindent 4 }} + {{- end }} + {{- if .Values.customAnnotations }} + {{- toYaml .Values.customAnnotations | nindent 4 }} + {{- end }} +{{- end }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/values.yaml new file mode 100644 index 0000000000..e3eeb388a0 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-adapter/values.yaml @@ -0,0 +1,292 @@ +affinity: {} + +topologySpreadConstraints: [] + +image: + repository: rancher/mirrored-prometheus-adapter-prometheus-adapter + # if not set appVersion field from Chart.yaml is used + tag: v0.12.0 + pullPolicy: IfNotPresent + +logLevel: 4 + +metricsRelistInterval: 1m + +listenPort: 6443 + +nodeSelector: {} + +priorityClassName: "" + +## Override the release namespace (for multi-namespace deployments in combined charts) +namespaceOverride: "" + +## Additional annotations to add to all resources +customAnnotations: {} + # role: custom-metrics + +## Additional labels to add to all resources +customLabels: {} + # monitoring: prometheus-adapter + +# Url to access prometheus +prometheus: + # Value is templated + url: http://prometheus.default.svc + port: 9090 + path: "" + +replicas: 1 + +# k8s 1.21 needs fsGroup to be set for non root deployments +# ref: https://github.com/kubernetes/kubernetes/issues/70679 +podSecurityContext: + fsGroup: 10001 + +# SecurityContext of the container +# ref. https://kubernetes.io/docs/tasks/configure-pod-container/security-context +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 10001 + seccompProfile: + type: RuntimeDefault + +rbac: + # Specifies whether RBAC resources should be created + create: true + # Specifies if a Cluster Role should be used for the Auth Reader + useAuthReaderClusterRole: false + externalMetrics: + resources: ["*"] + customMetrics: + resources: ["*"] + +psp: + # Specifies whether PSP resources should be created + create: false + # Annotations added to the pod security policy + 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 + +serviceAccount: + # Specifies whether a service account should be created + create: true + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: + # 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: {} + +# Custom DNS configuration to be added to prometheus-adapter pods +dnsConfig: {} + # nameservers: + # - 1.2.3.4 + # searches: + # - ns1.svc.cluster-domain.example + # - my.dns.search.suffix + # options: + # - name: ndots + # value: "2" + # - name: edns0 + +resources: {} + # requests: + # cpu: 100m + # memory: 128Mi + # limits: + # cpu: 100m + # memory: 128Mi + +# Configure liveness probe +# https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Probe +livenessProbe: + httpGet: + path: /healthz + port: https + scheme: HTTPS + initialDelaySeconds: 30 + timeoutSeconds: 5 + +# Configure readiness probe +readinessProbe: + httpGet: + path: /healthz + port: https + scheme: HTTPS + initialDelaySeconds: 30 + timeoutSeconds: 5 + +# Configure startup probe +# Use if prometheus-adapter takes a long time to finish startup e.g. polling a lot of API versions in cluster +startupProbe: {} + +rules: + default: true + + custom: [] + # - seriesQuery: '{__name__=~"^some_metric_count$"}' + # resources: + # template: <<.Resource>> + # name: + # matches: "" + # as: "my_custom_metric" + # metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>) + + # Mounts a configMap with pre-generated rules for use. Overrides the + # default, custom, external and resource entries + existing: + + external: [] + # - seriesQuery: '{__name__=~"^some_metric_count$"}' + # resources: + # template: <<.Resource>> + # name: + # matches: "" + # as: "my_external_metric" + # metricsQuery: sum(<<.Series>>{<<.LabelMatchers>>}) by (<<.GroupBy>>) + + # resource: + # cpu: + # containerQuery: | + # sum by (<<.GroupBy>>) ( + # rate(container_cpu_usage_seconds_total{container!="",<<.LabelMatchers>>}[3m]) + # ) + # nodeQuery: | + # sum by (<<.GroupBy>>) ( + # rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal",<<.LabelMatchers>>}[3m]) + # ) + # resources: + # overrides: + # node: + # resource: node + # namespace: + # resource: namespace + # pod: + # resource: pod + # containerLabel: container + # memory: + # containerQuery: | + # sum by (<<.GroupBy>>) ( + # avg_over_time(container_memory_working_set_bytes{container!="",<<.LabelMatchers>>}[3m]) + # ) + # nodeQuery: | + # sum by (<<.GroupBy>>) ( + # avg_over_time(node_memory_MemTotal_bytes{<<.LabelMatchers>>}[3m]) + # - + # avg_over_time(node_memory_MemAvailable_bytes{<<.LabelMatchers>>}[3m]) + # ) + # resources: + # overrides: + # node: + # resource: node + # namespace: + # resource: namespace + # pod: + # resource: pod + # containerLabel: container + # window: 3m + +service: + annotations: {} + port: 443 + type: ClusterIP + # clusterIP: 1.2.3.4 + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" +tls: + enable: false + ca: |- + # Public CA file that signed the APIService + key: |- + # Private key of the APIService + certificate: |- + # Public key of the APIService + +# Set environment variables from secrets, configmaps or by setting them as name/value +env: [] + # - name: TMP_DIR + # value: /tmp + # - name: PASSWORD + # valueFrom: + # secretKeyRef: + # name: mysecret + # key: password + # optional: false + +# Any extra arguments +extraArguments: [] + # - --tls-private-key-file=/etc/tls/tls.key + # - --tls-cert-file=/etc/tls/tls.crt + +# Additional containers to add to the pod +extraContainers: [] + +# Any extra volumes +extraVolumes: [] + # - name: example-name + # hostPath: + # path: /path/on/host + # type: DirectoryOrCreate + # - name: ssl-certs + # hostPath: + # path: /etc/ssl/certs/ca-bundle.crt + # type: File + +# Any extra volume mounts +extraVolumeMounts: [] + # - name: example-name + # mountPath: /path/in/container + # - name: ssl-certs + # mountPath: /etc/ssl/certs/ca-certificates.crt + # readOnly: true + +tolerations: [] + +# Labels added to the pod +podLabels: {} + +# Annotations added to the pod +podAnnotations: {} + +# Annotations added to the deployment +deploymentAnnotations: {} + +hostNetwork: + # Specifies if prometheus-adapter should be started in hostNetwork mode. + # + # You would require this enabled if you use alternate overlay networking for pods and + # API server unable to communicate with metrics-server. As an example, this is required + # if you use Weave network on EKS. See also dnsPolicy + enabled: false + +# When hostNetwork is enabled, you probably want to set this to ClusterFirstWithHostNet +# dnsPolicy: ClusterFirstWithHostNet + +# Deployment strategy type +strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 25% + maxSurge: 25% + +podDisruptionBudget: + # Specifies if PodDisruptionBudget should be enabled + # When enabled, minAvailable or maxUnavailable should also be defined. + enabled: false + minAvailable: + maxUnavailable: 1 + +certManager: + enabled: false + caCertDuration: 43800h0m0s + certDuration: 8760h0m0s diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/.helmignore new file mode 100644 index 0000000000..f0c1319444 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/.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/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/Chart.yaml new file mode 100644 index 0000000000..2afcc31034 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/Chart.yaml @@ -0,0 +1,25 @@ +annotations: + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: Chart Source + url: https://github.com/prometheus-community/helm-charts +apiVersion: v2 +appVersion: 1.8.2 +description: A Helm chart for prometheus node-exporter +home: https://github.com/prometheus/node_exporter/ +keywords: +- node-exporter +- prometheus +- exporter +maintainers: +- email: gianrubio@gmail.com + name: gianrubio +- email: zanhsieh@gmail.com + name: zanhsieh +- email: rootsandtrees@posteo.de + name: zeritti +name: prometheus-node-exporter +sources: +- https://github.com/prometheus/node_exporter/ +type: application +version: 4.37.1 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/README.md new file mode 100644 index 0000000000..ef83844102 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/README.md @@ -0,0 +1,96 @@ +# Prometheus Node Exporter + +Prometheus exporter for hardware and OS metrics exposed by *NIX kernels, written in Go with pluggable metric collectors. + +This chart bootstraps a Prometheus [Node Exporter](http://github.com/prometheus/node_exporter) daemonset on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Get Repository Info + +```console +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update +``` + +_See [helm repo](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Chart + +```console +helm install [RELEASE_NAME] prometheus-community/prometheus-node-exporter +``` + +_See [configuration](#configuring) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Uninstall Chart + +```console +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +## Upgrading Chart + +```console +helm upgrade [RELEASE_NAME] prometheus-community/prometheus-node-exporter --install +``` + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### 3.x to 4.x + +Starting from version 4.0.0, the `node exporter` chart is using the [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/). Therefore you have to delete the daemonset before you upgrade. + +```console +kubectl delete daemonset -l app=prometheus-node-exporter +helm upgrade -i prometheus-node-exporter prometheus-community/prometheus-node-exporter +``` + +If you use your own custom [ServiceMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor) or [PodMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#podmonitor), please ensure to upgrade their `selector` fields accordingly to the new labels. + +### From 2.x to 3.x + +Change the following: + +```yaml +hostRootFsMount: true +``` + +to: + +```yaml +hostRootFsMount: + enabled: true + mountPropagation: HostToContainer +``` + +## Configuring + +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, visit the chart's [values.yaml](./values.yaml), or run these configuration commands: + +```console +helm show values prometheus-community/prometheus-node-exporter +``` + +### kube-rbac-proxy + +You can enable `prometheus-node-exporter` endpoint protection using `kube-rbac-proxy`. By setting `kubeRBACProxy.enabled: true`, this chart will deploy a RBAC proxy container protecting the node-exporter endpoint. +To authorize access, authenticate your requests (via a `ServiceAccount` for example) with a `ClusterRole` attached such as: + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: prometheus-node-exporter-read +rules: + - apiGroups: [ "" ] + resources: ["services/node-exporter-prometheus-node-exporter"] + verbs: + - get +``` + +See [kube-rbac-proxy examples](https://github.com/brancz/kube-rbac-proxy/tree/master/examples/resource-attributes) for more details. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/NOTES.txt b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/NOTES.txt new file mode 100644 index 0000000000..db8584def8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/NOTES.txt @@ -0,0 +1,29 @@ +1. Get the application URL by running these commands: +{{- if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ template "prometheus-node-exporter.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "prometheus-node-exporter.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ template "prometheus-node-exporter.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc -w {{ template "prometheus-node-exporter.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ template "prometheus-node-exporter.namespace" . }} {{ template "prometheus-node-exporter.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ template "prometheus-node-exporter.namespace" . }} -l "app.kubernetes.io/name={{ template "prometheus-node-exporter.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:9100 to use your application" + kubectl port-forward --namespace {{ template "prometheus-node-exporter.namespace" . }} $POD_NAME 9100 +{{- end }} + +{{- if .Values.kubeRBACProxy.enabled}} + +kube-rbac-proxy endpoint protections is enabled: +- Metrics endpoints is now HTTPS +- Ensure that the client authenticates the requests (e.g. via service account) with the following role permissions: +``` +rules: + - apiGroups: [ "" ] + resources: ["services/{{ template "prometheus-node-exporter.fullname" . }}"] + verbs: + - get +``` +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/_helpers.tpl new file mode 100644 index 0000000000..72a6db45a1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/_helpers.tpl @@ -0,0 +1,236 @@ +# Rancher +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "prometheus-node-exporter.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 "prometheus-node-exporter.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 "prometheus-node-exporter.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "prometheus-node-exporter.labels" -}} +helm.sh/chart: {{ include "prometheus-node-exporter.chart" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: metrics +app.kubernetes.io/part-of: {{ include "prometheus-node-exporter.name" . }} +{{ include "prometheus-node-exporter.selectorLabels" . }} +{{- with .Chart.AppVersion }} +app.kubernetes.io/version: {{ . | quote }} +{{- end }} +{{- with .Values.podLabels }} +{{ toYaml . }} +{{- end }} +{{- if .Values.releaseLabel }} +release: {{ .Release.Name }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "prometheus-node-exporter.selectorLabels" -}} +app.kubernetes.io/name: {{ include "prometheus-node-exporter.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "prometheus-node-exporter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "prometheus-node-exporter.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +The image to use +*/}} +{{- define "prometheus-node-exporter.image" -}} +{{- $temp_registry := (include "system_default_registry" .) }} +{{- if .Values.image.sha }} +{{- fail "image.sha forbidden. Use image.digest instead" }} +{{- else if .Values.image.digest }} +{{- if $temp_registry }} +{{- printf "%s%s:%s@%s" $temp_registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) .Values.image.digest }} +{{- else if .Values.global.imageRegistry }} +{{- printf "%s/%s:%s@%s" .Values.global.imageRegistry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) .Values.image.digest }} +{{- else }} +{{- printf "%s/%s:%s@%s" .Values.image.registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) .Values.image.digest }} +{{- end }} +{{- else }} +{{- if $temp_registry }} +{{- printf "%s%s:%s" $temp_registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }} +{{- else if .Values.global.imageRegistry }} +{{- printf "%s/%s:%s" .Values.global.imageRegistry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }} +{{- else }} +{{- printf "%s/%s:%s" .Values.image.registry .Values.image.repository (default (printf "v%s" .Chart.AppVersion) .Values.image.tag) }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "prometheus-node-exporter.namespace" -}} +{{- if .Values.namespaceOverride }} +{{- .Values.namespaceOverride }} +{{- else }} +{{- .Release.Namespace }} +{{- end }} +{{- end }} + +{{/* +Create the namespace name of the service monitor +*/}} +{{- define "prometheus-node-exporter.monitor-namespace" -}} +{{- if .Values.namespaceOverride }} +{{- .Values.namespaceOverride }} +{{- else }} +{{- if .Values.prometheus.monitor.namespace }} +{{- .Values.prometheus.monitor.namespace }} +{{- else }} +{{- .Release.Namespace }} +{{- end }} +{{- end }} +{{- end }} + +{{/* Sets default scrape limits for servicemonitor */}} +{{- define "servicemonitor.scrapeLimits" -}} +{{- with .sampleLimit }} +sampleLimit: {{ . }} +{{- end }} +{{- with .targetLimit }} +targetLimit: {{ . }} +{{- end }} +{{- with .labelLimit }} +labelLimit: {{ . }} +{{- end }} +{{- with .labelNameLengthLimit }} +labelNameLengthLimit: {{ . }} +{{- end }} +{{- with .labelValueLengthLimit }} +labelValueLengthLimit: {{ . }} +{{- end }} +{{- end }} + +{{/* +Formats imagePullSecrets. Input is (dict "Values" .Values "imagePullSecrets" .{specific imagePullSecrets}) +*/}} +{{- define "prometheus-node-exporter.imagePullSecrets" -}} +{{- range (concat .Values.global.imagePullSecrets .imagePullSecrets) }} + {{- if eq (typeOf .) "map[string]interface {}" }} +- {{ toYaml . | trim }} + {{- else }} +- name: {{ . }} + {{- end }} +{{- end }} +{{- end -}} + +{{/* +Create the namespace name of the pod monitor +*/}} +{{- define "prometheus-node-exporter.podmonitor-namespace" -}} +{{- if .Values.namespaceOverride }} +{{- .Values.namespaceOverride }} +{{- else }} +{{- if .Values.prometheus.podMonitor.namespace }} +{{- .Values.prometheus.podMonitor.namespace }} +{{- else }} +{{- .Release.Namespace }} +{{- end }} +{{- end }} +{{- end }} + +{{/* Sets default scrape limits for podmonitor */}} +{{- define "podmonitor.scrapeLimits" -}} +{{- with .sampleLimit }} +sampleLimit: {{ . }} +{{- end }} +{{- with .targetLimit }} +targetLimit: {{ . }} +{{- end }} +{{- with .labelLimit }} +labelLimit: {{ . }} +{{- end }} +{{- with .labelNameLengthLimit }} +labelNameLengthLimit: {{ . }} +{{- end }} +{{- with .labelValueLengthLimit }} +labelValueLengthLimit: {{ . }} +{{- end }} +{{- end }} + +{{/* Sets sidecar volumeMounts */}} +{{- define "prometheus-node-exporter.sidecarVolumeMounts" -}} +{{- range $_, $mount := $.Values.sidecarVolumeMount }} +- name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + readOnly: {{ $mount.readOnly }} +{{- end }} +{{- range $_, $mount := $.Values.sidecarHostVolumeMounts }} +- name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + readOnly: {{ $mount.readOnly }} +{{- if $mount.mountPropagation }} + mountPropagation: {{ $mount.mountPropagation }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/clusterrole.yaml new file mode 100644 index 0000000000..c256dba73d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/clusterrole.yaml @@ -0,0 +1,19 @@ +{{- if and (eq .Values.rbac.create true) (eq .Values.kubeRBACProxy.enabled true) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} +rules: + {{- if $.Values.kubeRBACProxy.enabled }} + - apiGroups: [ "authentication.k8s.io" ] + resources: + - tokenreviews + verbs: [ "create" ] + - apiGroups: [ "authorization.k8s.io" ] + resources: + - subjectaccessreviews + verbs: [ "create" ] + {{- end }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/clusterrolebinding.yaml new file mode 100644 index 0000000000..653305ad9e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and (eq .Values.rbac.create true) (eq .Values.kubeRBACProxy.enabled true) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} + name: {{ template "prometheus-node-exporter.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole +{{- if .Values.rbac.useExistingRole }} + name: {{ .Values.rbac.useExistingRole }} +{{- else }} + name: {{ template "prometheus-node-exporter.fullname" . }} +{{- end }} +subjects: +- kind: ServiceAccount + name: {{ template "prometheus-node-exporter.serviceAccountName" . }} + namespace: {{ template "prometheus-node-exporter.namespace" . }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/daemonset.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/daemonset.yaml new file mode 100644 index 0000000000..7f91a8d2b1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/daemonset.yaml @@ -0,0 +1,312 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} + {{- with .Values.daemonsetAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "prometheus-node-exporter.selectorLabels" . | nindent 6 }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + {{- with .Values.updateStrategy }} + updateStrategy: + {{- toYaml . | nindent 4 }} + {{- end }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 8 }} + spec: + automountServiceAccountToken: {{ ternary true false (or .Values.serviceAccount.automountServiceAccountToken .Values.kubeRBACProxy.enabled) }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.extraInitContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "prometheus-node-exporter.serviceAccountName" . }} + {{- with .Values.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ . }} + {{- end }} + containers: + {{- $servicePort := ternary .Values.kubeRBACProxy.port .Values.service.port .Values.kubeRBACProxy.enabled }} + - name: node-exporter + image: {{ include "prometheus-node-exporter.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - --path.procfs=/host/proc + - --path.sysfs=/host/sys + {{- if .Values.hostRootFsMount.enabled }} + - --path.rootfs=/host/root + {{- if semverCompare ">=1.4.0-0" (coalesce .Values.version .Values.image.tag .Chart.AppVersion) }} + - --path.udev.data=/host/root/run/udev/data + {{- end }} + {{- end }} + - --web.listen-address=[$(HOST_IP)]:{{ $servicePort }} + {{- with .Values.extraArgs }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.containerSecurityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + env: + - name: HOST_IP + {{- if .Values.kubeRBACProxy.enabled }} + value: 127.0.0.1 + {{- else if .Values.service.listenOnAllInterfaces }} + value: 0.0.0.0 + {{- else }} + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.hostIP + {{- end }} + {{- range $key, $value := .Values.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- if eq .Values.kubeRBACProxy.enabled false }} + ports: + - name: {{ .Values.service.portName }} + containerPort: {{ .Values.service.port }} + protocol: TCP + {{- end }} + livenessProbe: + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + httpGet: + {{- if .Values.kubeRBACProxy.enabled }} + host: 127.0.0.1 + {{- end }} + httpHeaders: + {{- range $_, $header := .Values.livenessProbe.httpGet.httpHeaders }} + - name: {{ $header.name }} + value: {{ $header.value }} + {{- end }} + path: / + port: {{ $servicePort }} + scheme: {{ upper .Values.livenessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + readinessProbe: + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + {{- if .Values.kubeRBACProxy.enabled }} + host: 127.0.0.1 + {{- end }} + httpHeaders: + {{- range $_, $header := .Values.readinessProbe.httpGet.httpHeaders }} + - name: {{ $header.name }} + value: {{ $header.value }} + {{- end }} + path: / + port: {{ $servicePort }} + scheme: {{ upper .Values.readinessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- if .Values.terminationMessageParams.enabled }} + {{- with .Values.terminationMessageParams }} + terminationMessagePath: {{ .terminationMessagePath }} + terminationMessagePolicy: {{ .terminationMessagePolicy }} + {{- end }} + {{- end }} + volumeMounts: + - name: proc + mountPath: /host/proc + {{- with .Values.hostProcFsMount.mountPropagation }} + mountPropagation: {{ . }} + {{- end }} + readOnly: true + - name: sys + mountPath: /host/sys + {{- with .Values.hostSysFsMount.mountPropagation }} + mountPropagation: {{ . }} + {{- end }} + readOnly: true + {{- if .Values.hostRootFsMount.enabled }} + - name: root + mountPath: /host/root + {{- with .Values.hostRootFsMount.mountPropagation }} + mountPropagation: {{ . }} + {{- end }} + readOnly: true + {{- end }} + {{- range $_, $mount := .Values.extraHostVolumeMounts }} + - name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + readOnly: {{ $mount.readOnly }} + {{- with $mount.mountPropagation }} + mountPropagation: {{ . }} + {{- end }} + {{- end }} + {{- range $_, $mount := .Values.sidecarVolumeMount }} + - name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + readOnly: true + {{- end }} + {{- range $_, $mount := .Values.configmaps }} + - name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + {{- end }} + {{- range $_, $mount := .Values.secrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + {{- end }} + {{- range .Values.sidecars }} + {{- $overwrites := dict "volumeMounts" (concat (include "prometheus-node-exporter.sidecarVolumeMounts" $ | fromYamlArray) (.volumeMounts | default list) | default list) }} + {{- $defaults := dict "image" (include "prometheus-node-exporter.image" $) "securityContext" $.Values.containerSecurityContext "imagePullPolicy" $.Values.image.pullPolicy }} + - {{- toYaml (merge $overwrites . $defaults) | nindent 10 }} + {{- end }} + {{- if .Values.kubeRBACProxy.enabled }} + - name: kube-rbac-proxy + args: + {{- if .Values.kubeRBACProxy.extraArgs }} + {{- .Values.kubeRBACProxy.extraArgs | toYaml | nindent 12 }} + {{- end }} + - --secure-listen-address=:{{ .Values.service.port}} + - --upstream=http://127.0.0.1:{{ $servicePort }}/ + - --proxy-endpoints-port={{ .Values.kubeRBACProxy.proxyEndpointsPort }} + - --config-file=/etc/kube-rbac-proxy-config/config-file.yaml + volumeMounts: + - name: kube-rbac-proxy-config + mountPath: /etc/kube-rbac-proxy-config + imagePullPolicy: {{ .Values.kubeRBACProxy.image.pullPolicy }} + {{- $base_registry := (include "monitoring_registry" .) }} + {{- if .Values.kubeRBACProxy.image.sha }} + image: "{{ $base_registry | default .Values.kubeRBACProxy.image.registry}}/{{ .Values.kubeRBACProxy.image.repository }}:{{ .Values.kubeRBACProxy.image.tag }}@sha256:{{ .Values.kubeRBACProxy.image.sha }}" + {{- else }} + image: "{{ $base_registry | default .Values.kubeRBACProxy.image.registry}}/{{ .Values.kubeRBACProxy.image.repository }}:{{ .Values.kubeRBACProxy.image.tag }}" + {{- end }} + ports: + - containerPort: {{ .Values.service.port}} + name: {{ .Values.kubeRBACProxy.portName }} + {{- if .Values.kubeRBACProxy.enableHostPort }} + hostPort: {{ .Values.service.port }} + {{- end }} + - containerPort: {{ .Values.kubeRBACProxy.proxyEndpointsPort }} + {{- if .Values.kubeRBACProxy.enableProxyEndpointsHostPort }} + hostPort: {{ .Values.kubeRBACProxy.proxyEndpointsPort }} + {{- end }} + name: "http-healthz" + readinessProbe: + httpGet: + scheme: HTTPS + port: {{ .Values.kubeRBACProxy.proxyEndpointsPort }} + path: healthz + initialDelaySeconds: 5 + timeoutSeconds: 5 + {{- if .Values.kubeRBACProxy.resources }} + resources: + {{- toYaml .Values.kubeRBACProxy.resources | nindent 12 }} + {{- end }} + {{- if .Values.terminationMessageParams.enabled }} + {{- with .Values.terminationMessageParams }} + terminationMessagePath: {{ .terminationMessagePath }} + terminationMessagePolicy: {{ .terminationMessagePolicy }} + {{- end }} + {{- end }} + {{- with .Values.kubeRBACProxy.env }} + env: + {{- range $key, $value := $.Values.kubeRBACProxy.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- if .Values.kubeRBACProxy.containerSecurityContext }} + securityContext: + {{ toYaml .Values.kubeRBACProxy.containerSecurityContext | nindent 12 }} + {{- end }} + {{- end }} + {{- if or .Values.imagePullSecrets .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- include "prometheus-node-exporter.imagePullSecrets" (dict "Values" .Values "imagePullSecrets" .Values.imagePullSecrets) | indent 8 }} + {{- end }} + hostNetwork: {{ .Values.hostNetwork }} + hostPID: {{ .Values.hostPID }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.dnsConfig }} + dnsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.restartPolicy }} + restartPolicy: {{ . }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: proc + hostPath: + path: /proc + - name: sys + hostPath: + path: /sys + {{- if .Values.hostRootFsMount.enabled }} + - name: root + hostPath: + path: / + {{- end }} + {{- range $_, $mount := .Values.extraHostVolumeMounts }} + - name: {{ $mount.name }} + hostPath: + path: {{ $mount.hostPath }} + {{- with $mount.type }} + type: {{ . }} + {{- end }} + {{- end }} + {{- range $_, $mount := .Values.sidecarVolumeMount }} + - name: {{ $mount.name }} + emptyDir: + medium: Memory + {{- end }} + {{- range $_, $mount := .Values.sidecarHostVolumeMounts }} + - name: {{ $mount.name }} + hostPath: + path: {{ $mount.hostPath }} + {{- end }} + {{- range $_, $mount := .Values.configmaps }} + - name: {{ $mount.name }} + configMap: + name: {{ $mount.name }} + {{- end }} + {{- range $_, $mount := .Values.secrets }} + - name: {{ $mount.name }} + secret: + secretName: {{ $mount.name }} + {{- end }} + {{- if .Values.kubeRBACProxy.enabled }} + - name: kube-rbac-proxy-config + configMap: + name: {{ template "prometheus-node-exporter.fullname" . }}-rbac-config + {{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/endpoints.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/endpoints.yaml new file mode 100644 index 0000000000..56b695203a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/endpoints.yaml @@ -0,0 +1,18 @@ +{{- if .Values.endpoints }} +apiVersion: v1 +kind: Endpoints +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} +subsets: + - addresses: + {{- range .Values.endpoints }} + - ip: {{ . }} + {{- end }} + ports: + - name: {{ .Values.service.portName }} + port: {{ .Values.service.port }} + protocol: TCP +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/extra-manifests.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/extra-manifests.yaml new file mode 100644 index 0000000000..2b21b71062 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/extra-manifests.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraManifests }} +--- +{{ tpl . $ }} +{{ end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/networkpolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/networkpolicy.yaml new file mode 100644 index 0000000000..825722729d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/networkpolicy.yaml @@ -0,0 +1,23 @@ +{{- if .Values.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" $ | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + ingress: + - ports: + - port: {{ .Values.service.port }} + policyTypes: + - Egress + - Ingress + podSelector: + matchLabels: + {{- include "prometheus-node-exporter.selectorLabels" . | nindent 6 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/podmonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/podmonitor.yaml new file mode 100644 index 0000000000..f88da6a34e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/podmonitor.yaml @@ -0,0 +1,91 @@ +{{- if .Values.prometheus.podMonitor.enabled }} +apiVersion: {{ .Values.prometheus.podMonitor.apiVersion | default "monitoring.coreos.com/v1" }} +kind: PodMonitor +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.podmonitor-namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} + {{- with .Values.prometheus.podMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ default "app.kubernetes.io/name" .Values.prometheus.podMonitor.jobLabel }} + {{- include "podmonitor.scrapeLimits" .Values.prometheus.podMonitor | nindent 2 }} + selector: + matchLabels: + {{- with .Values.prometheus.podMonitor.selectorOverride }} + {{- toYaml . | nindent 6 }} + {{- else }} + {{- include "prometheus-node-exporter.selectorLabels" . | nindent 6 }} + {{- end }} + namespaceSelector: + matchNames: + - {{ include "prometheus-node-exporter.namespace" . }} + {{- with .Values.prometheus.podMonitor.attachMetadata }} + attachMetadata: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.podTargetLabels }} + podTargetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} + podMetricsEndpoints: + - port: {{ .Values.service.portName }} + {{- with .Values.prometheus.podMonitor.scheme }} + scheme: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.path }} + path: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.basicAuth }} + basicAuth: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.bearerTokenSecret }} + bearerTokenSecret: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.authorization }} + authorization: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.oauth2 }} + oauth2: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.proxyUrl }} + proxyUrl: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.honorTimestamps }} + honorTimestamps: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.honorLabels }} + honorLabels: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + enableHttp2: {{ default false .Values.prometheus.podMonitor.enableHttp2 }} + filterRunning: {{ default true .Values.prometheus.podMonitor.filterRunning }} + followRedirects: {{ default false .Values.prometheus.podMonitor.followRedirects }} + {{- with .Values.prometheus.podMonitor.params }} + params: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp-clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp-clusterrole.yaml new file mode 100644 index 0000000000..8957317243 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp-clusterrole.yaml @@ -0,0 +1,14 @@ +{{- if and .Values.rbac.create .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: psp-{{ include "prometheus-node-exporter.fullname" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} +rules: +- apiGroups: ['extensions'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ include "prometheus-node-exporter.fullname" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp-clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp-clusterrolebinding.yaml new file mode 100644 index 0000000000..333370173b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp-clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.rbac.create .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: psp-{{ include "prometheus-node-exporter.fullname" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: psp-{{ include "prometheus-node-exporter.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp.yaml new file mode 100644 index 0000000000..4896c84daa --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/psp.yaml @@ -0,0 +1,49 @@ +{{- if and .Values.rbac.create .Values.rbac.pspEnabled (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} + {{- with .Values.rbac.pspAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + privileged: false + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + - 'persistentVolumeClaim' + - 'hostPath' + hostNetwork: true + hostIPC: false + hostPID: true + hostPorts: + - min: 0 + max: 65535 + 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: + # Allow adding the root group. + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Allow adding the root group. + - min: 0 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/rbac-configmap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/rbac-configmap.yaml new file mode 100644 index 0000000000..814e110337 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/rbac-configmap.yaml @@ -0,0 +1,16 @@ +{{- if .Values.kubeRBACProxy.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "prometheus-node-exporter.fullname" . }}-rbac-config + namespace: {{ include "prometheus-node-exporter.namespace" . }} +data: + config-file.yaml: |+ + authorization: + resourceAttributes: + namespace: {{ template "prometheus-node-exporter.namespace" . }} + apiVersion: v1 + resource: services + subresource: {{ template "prometheus-node-exporter.fullname" . }} + name: {{ template "prometheus-node-exporter.fullname" . }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/service.yaml new file mode 100644 index 0000000000..8308b7b2b3 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/service.yaml @@ -0,0 +1,35 @@ +{{- if .Values.service.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" $ | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.service.ipDualStack.ipFamilyPolicy }} +{{- end }} +{{- if .Values.service.externalTrafficPolicy }} + externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }} +{{- end }} + type: {{ .Values.service.type }} +{{- if and (eq .Values.service.type "ClusterIP") .Values.service.clusterIP }} + clusterIP: "{{ .Values.service.clusterIP }}" +{{- end }} + ports: + - port: {{ .Values.service.port }} + {{- if ( and (eq .Values.service.type "NodePort" ) (not (empty .Values.service.nodePort)) ) }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + targetPort: {{ .Values.service.targetPort }} + protocol: TCP + name: {{ .Values.service.portName }} + selector: + {{- include "prometheus-node-exporter.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/serviceaccount.yaml new file mode 100644 index 0000000000..462b0cda4b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.rbac.create .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "prometheus-node-exporter.serviceAccountName" . }} + namespace: {{ include "prometheus-node-exporter.namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- if or .Values.serviceAccount.imagePullSecrets .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- include "prometheus-node-exporter.imagePullSecrets" (dict "Values" .Values "imagePullSecrets" .Values.serviceAccount.imagePullSecrets) | indent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/servicemonitor.yaml new file mode 100644 index 0000000000..abe6c73c1b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/servicemonitor.yaml @@ -0,0 +1,71 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: {{ .Values.prometheus.monitor.apiVersion | default "monitoring.coreos.com/v1" }} +kind: ServiceMonitor +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.monitor-namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} + {{- with .Values.prometheus.monitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ default "app.kubernetes.io/name" .Values.prometheus.monitor.jobLabel }} + {{- include "servicemonitor.scrapeLimits" .Values.prometheus.monitor | nindent 2 }} + {{- with .Values.prometheus.monitor.podTargetLabels }} + podTargetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- with .Values.prometheus.monitor.selectorOverride }} + {{- toYaml . | nindent 6 }} + {{- else }} + {{- include "prometheus-node-exporter.selectorLabels" . | nindent 6 }} + {{- end }} + {{- with .Values.prometheus.monitor.attachMetadata }} + attachMetadata: + {{- toYaml . | nindent 4 }} + {{- end }} + endpoints: + - port: {{ .Values.service.portName }} + scheme: {{ .Values.prometheus.monitor.scheme }} + {{- with .Values.prometheus.monitor.basicAuth }} + basicAuth: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.monitor.bearerTokenFile }} + bearerTokenFile: {{ . }} + {{- end }} + {{- with .Values.prometheus.monitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.monitor.proxyUrl }} + proxyUrl: {{ . }} + {{- end }} + {{- with .Values.prometheus.monitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.prometheus.monitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + {{- with .Values.prometheus.monitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + metricRelabelings: + {{- with .Values.prometheus.monitor.metricRelabelings }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName }} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/verticalpodautoscaler.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/verticalpodautoscaler.yaml new file mode 100644 index 0000000000..2c2705f872 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/templates/verticalpodautoscaler.yaml @@ -0,0 +1,40 @@ +{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1") (.Values.verticalPodAutoscaler.enabled) }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: {{ include "prometheus-node-exporter.fullname" . }} + namespace: {{ include "prometheus-node-exporter.namespace" . }} + labels: + {{- include "prometheus-node-exporter.labels" . | nindent 4 }} +spec: + {{- with .Values.verticalPodAutoscaler.recommenders }} + recommenders: + {{- toYaml . | nindent 4 }} + {{- end }} + resourcePolicy: + containerPolicies: + - containerName: node-exporter + {{- with .Values.verticalPodAutoscaler.controlledResources }} + controlledResources: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.verticalPodAutoscaler.controlledValues }} + controlledValues: {{ . }} + {{- end }} + {{- with .Values.verticalPodAutoscaler.maxAllowed }} + maxAllowed: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.verticalPodAutoscaler.minAllowed }} + minAllowed: + {{- toYaml . | nindent 8 }} + {{- end }} + targetRef: + apiVersion: apps/v1 + kind: DaemonSet + name: {{ include "prometheus-node-exporter.fullname" . }} + {{- with .Values.verticalPodAutoscaler.updatePolicy }} + updatePolicy: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/values.yaml new file mode 100644 index 0000000000..b02d92650a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/prometheus-node-exporter/values.yaml @@ -0,0 +1,539 @@ +# Default values for prometheus-node-exporter. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + registry: docker.io + repository: rancher/mirrored-prometheus-node-exporter + # Overrides the image tag whose default is {{ printf "v%s" .Chart.AppVersion }} + tag: v1.8.2 + pullPolicy: IfNotPresent + digest: "" + +imagePullSecrets: [] +# - name: "image-pull-secret" +nameOverride: "" +fullnameOverride: "" + +# Number of old history to retain to allow rollback +# Default Kubernetes value is set to 10 +revisionHistoryLimit: 10 + +global: + cattle: + systemDefaultRegistry: "" + + # To help compatibility with other charts which use global.imagePullSecrets. + # Allow either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style). + # global: + # imagePullSecrets: + # - name: pullSecret1 + # - name: pullSecret2 + # or + # global: + # imagePullSecrets: + # - pullSecret1 + # - pullSecret2 + imagePullSecrets: [] + # + # Allow parent charts to override registry hostname + imageRegistry: "" + +# Configure kube-rbac-proxy. When enabled, creates a kube-rbac-proxy to protect the node-exporter http endpoint. +# The requests are served through the same service but requests are HTTPS. +kubeRBACProxy: + enabled: false + ## Set environment variables as name/value pairs + env: {} + # VARIABLE: value + image: + registry: docker.io + repository: rancher/mirrored-brancz-kube-rbac-proxy + tag: v0.18.0 + sha: "" + pullPolicy: IfNotPresent + + # List of additional cli arguments to configure kube-rbac-proxy + # for example: --tls-cipher-suites, --log-file, etc. + # all the possible args can be found here: https://github.com/brancz/kube-rbac-proxy#usage + extraArgs: [] + + ## Specify security settings for a Container + ## Allows overrides and additional options compared to (Pod) securityContext + ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + containerSecurityContext: {} + + # Specify the port used for the Node exporter container (upstream port) + port: 8100 + # Specify the name of the container port + portName: http + # Configure a hostPort. If true, hostPort will be enabled in the container and set to service.port. + enableHostPort: false + + # Configure Proxy Endpoints Port + # This is the port being probed for readiness + proxyEndpointsPort: 8888 + # Configure a hostPort. If true, hostPort will be enabled in the container and set to proxyEndpointsPort. + enableProxyEndpointsHostPort: false + + 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 + +service: + enabled: true + type: ClusterIP + clusterIP: "" + port: 9796 + targetPort: 9796 + nodePort: + portName: metrics + listenOnAllInterfaces: true + annotations: + prometheus.io/scrape: "true" + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + externalTrafficPolicy: "" + +# Set a NetworkPolicy with: +# ingress only on service.port +# no egress permitted +networkPolicy: + enabled: false + +# Additional environment variables that will be passed to the daemonset +env: {} +## env: +## VARIABLE: value + +prometheus: + monitor: + enabled: false + additionalLabels: {} + namespace: "" + + jobLabel: "" + + # List of pod labels to add to node exporter metrics + # https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor + podTargetLabels: [] + + scheme: http + basicAuth: {} + bearerTokenFile: + tlsConfig: {} + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## Override serviceMonitor selector + ## + selectorOverride: {} + + ## Attach node metadata to discovered targets. Requires Prometheus v2.35.0 and above. + ## + attachMetadata: + node: false + + relabelings: [] + metricRelabelings: [] + interval: "" + scrapeTimeout: 10s + ## prometheus.monitor.apiVersion ApiVersion for the serviceMonitor Resource(defaults to "monitoring.coreos.com/v1") + apiVersion: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + # PodMonitor defines monitoring for a set of pods. + # ref. https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.PodMonitor + # Using a PodMonitor may be preferred in some environments where there is very large number + # of Node Exporter endpoints (1000+) behind a single service. + # The PodMonitor is disabled by default. When switching from ServiceMonitor to PodMonitor, + # the time series resulting from the configuration through PodMonitor may have different labels. + # For instance, there will not be the service label any longer which might + # affect PromQL queries selecting that label. + podMonitor: + enabled: false + # Namespace in which to deploy the pod monitor. Defaults to the release namespace. + namespace: "" + # Additional labels, e.g. setting a label for pod monitor selector as set in prometheus + additionalLabels: {} + # release: kube-prometheus-stack + # PodTargetLabels transfers labels of the Kubernetes Pod onto the target. + podTargetLabels: [] + # apiVersion defaults to monitoring.coreos.com/v1. + apiVersion: "" + # Override pod selector to select pod objects. + selectorOverride: {} + # Attach node metadata to discovered targets. Requires Prometheus v2.35.0 and above. + attachMetadata: + node: false + # The label to use to retrieve the job name from. Defaults to label app.kubernetes.io/name. + jobLabel: "" + + # Scheme/protocol to use for scraping. + scheme: "http" + # Path to scrape metrics at. + path: "/metrics" + + # BasicAuth allow an endpoint to authenticate over basic authentication. + # More info: https://prometheus.io/docs/operating/configuration/#endpoint + basicAuth: {} + # Secret to mount to read bearer token for scraping targets. + # The secret needs to be in the same namespace as the pod monitor and accessible by the Prometheus Operator. + # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#secretkeyselector-v1-core + bearerTokenSecret: {} + # TLS configuration to use when scraping the endpoint. + tlsConfig: {} + # Authorization section for this endpoint. + # https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.SafeAuthorization + authorization: {} + # OAuth2 for the URL. Only valid in Prometheus versions 2.27.0 and newer. + # https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.OAuth2 + oauth2: {} + + # ProxyURL eg http://proxyserver:2195. Directs scrapes through proxy to this endpoint. + proxyUrl: "" + # Interval at which endpoints should be scraped. If not specified Prometheus’ global scrape interval is used. + interval: "" + # Timeout after which the scrape is ended. If not specified, the Prometheus global scrape interval is used. + scrapeTimeout: "" + # HonorTimestamps controls whether Prometheus respects the timestamps present in scraped data. + honorTimestamps: true + # HonorLabels chooses the metric’s labels on collisions with target labels. + honorLabels: true + # Whether to enable HTTP2. Default false. + enableHttp2: "" + # Drop pods that are not running. (Failed, Succeeded). + # Enabled by default. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase + filterRunning: "" + # FollowRedirects configures whether scrape requests follow HTTP 3xx redirects. Default false. + followRedirects: "" + # Optional HTTP URL parameters + params: {} + + # RelabelConfigs to apply to samples before scraping. Prometheus Operator automatically adds + # relabelings for a few standard Kubernetes fields. The original scrape job’s name + # is available via the __tmp_prometheus_job_name label. + # More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + relabelings: [] + # MetricRelabelConfigs to apply to samples before ingestion. + metricRelabelings: [] + + # SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + sampleLimit: 0 + # TargetLimit defines a limit on the number of scraped targets that will be accepted. + targetLimit: 0 + # Per-scrape limit on number of labels that will be accepted for a sample. + # Only valid in Prometheus versions 2.27.0 and newer. + labelLimit: 0 + # Per-scrape limit on length of labels name that will be accepted for a sample. + # Only valid in Prometheus versions 2.27.0 and newer. + labelNameLengthLimit: 0 + # Per-scrape limit on length of labels value that will be accepted for a sample. + # Only valid in Prometheus versions 2.27.0 and newer. + labelValueLengthLimit: 0 + +## Customize the updateStrategy if set +updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + +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: 200m + # memory: 50Mi + # requests: + # cpu: 100m + # memory: 30Mi + +# Specify the container restart policy passed to the Node Export container +# Possible Values: Always (default)|OnFailure|Never +restartPolicy: null + +serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + name: + annotations: {} + imagePullSecrets: [] + automountServiceAccountToken: false + +securityContext: + fsGroup: 65534 + runAsGroup: 65534 + runAsNonRoot: true + runAsUser: 65534 + +containerSecurityContext: + readOnlyRootFilesystem: true + # capabilities: + # add: + # - SYS_TIME + +rbac: + ## If true, create & use RBAC resources + ## + create: true + ## If true, create & use Pod Security Policy resources + ## https://kubernetes.io/docs/concepts/policy/pod-security-policy/ + pspEnabled: true + pspAnnotations: {} + +# for deployments that have node_exporter deployed outside of the cluster, list +# their addresses here +endpoints: [] + +# Expose the service to the host network +hostNetwork: true + +# Share the host process ID namespace +hostPID: true + +# Mount the node's root file system (/) at /host/root in the container +hostRootFsMount: + enabled: true + # Defines how new mounts in existing mounts on the node or in the container + # are propagated to the container or node, respectively. Possible values are + # None, HostToContainer, and Bidirectional. If this field is omitted, then + # None is used. More information on: + # https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation + mountPropagation: HostToContainer + +# Mount the node's proc file system (/proc) at /host/proc in the container +hostProcFsMount: + # Possible values are None, HostToContainer, and Bidirectional + mountPropagation: "" + +# Mount the node's sys file system (/sys) at /host/sys in the container +hostSysFsMount: + # Possible values are None, HostToContainer, and Bidirectional + mountPropagation: "" + +## Assign a group of affinity scheduling rules +## +affinity: {} +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchFields: +# - key: metadata.name +# operator: In +# values: +# - target-host-name + +# Annotations to be added to node exporter pods +podAnnotations: + # Fix for very slow GKE cluster upgrades + cluster-autoscaler.kubernetes.io/safe-to-evict: "true" + +# Extra labels to be added to node exporter pods +podLabels: {} + +# Annotations to be added to node exporter daemonset +daemonsetAnnotations: {} + +## set to true to add the release label so scraping of the servicemonitor with kube-prometheus-stack works out of the box +releaseLabel: false + +# Custom DNS configuration to be added to prometheus-node-exporter pods +dnsConfig: {} +# nameservers: +# - 1.2.3.4 +# searches: +# - ns1.svc.cluster-domain.example +# - my.dns.search.suffix +# options: +# - name: ndots +# value: "2" +# - name: edns0 + +## Assign a nodeSelector if operating a hybrid cluster +## +nodeSelector: + kubernetes.io/os: linux + # kubernetes.io/arch: amd64 + +# Specify grace period for graceful termination of pods. Defaults to 30 if null or not specified +terminationGracePeriodSeconds: null + +tolerations: + - effect: NoSchedule + operator: Exists + - effect: NoExecute + operator: Exists + +# Enable or disable container termination message settings +# https://kubernetes.io/docs/tasks/debug/debug-application/determine-reason-pod-failure/ +terminationMessageParams: + enabled: false + # If enabled, specify the path for termination messages + terminationMessagePath: /dev/termination-log + # If enabled, specify the policy for termination messages + terminationMessagePolicy: File + + +## Assign a PriorityClassName to pods if set +# priorityClassName: "" + +## Additional container arguments +## +extraArgs: [] +# - --collector.diskstats.ignored-devices=^(ram|loop|fd|(h|s|v)d[a-z]|nvme\\d+n\\d+p)\\d+$ +# - --collector.textfile.directory=/run/prometheus + +## Additional mounts from the host to node-exporter container +## +extraHostVolumeMounts: [] +# - name: +# hostPath: +# https://kubernetes.io/docs/concepts/storage/volumes/#hostpath-volume-types +# type: "" (Default)|DirectoryOrCreate|Directory|FileOrCreate|File|Socket|CharDevice|BlockDevice +# mountPath: +# readOnly: true|false +# mountPropagation: None|HostToContainer|Bidirectional + +## Additional configmaps to be mounted. +## +configmaps: [] +# - name: +# mountPath: +secrets: [] +# - name: +# mountPath: +## Override the deployment namespace +## +namespaceOverride: "" + +## Additional containers for export metrics to text file; fields image,imagePullPolicy,securityContext take default value from main container +## +sidecars: [] +# - name: nvidia-dcgm-exporter +# image: nvidia/dcgm-exporter:1.4.3 +# volumeMounts: +# - name: tmp +# mountPath: /tmp + +## Volume for sidecar containers +## +sidecarVolumeMount: [] +# - name: collector-textfiles +# mountPath: /run/prometheus +# readOnly: false + +## Additional mounts from the host to sidecar containers +## +sidecarHostVolumeMounts: [] +# - name: +# hostPath: +# mountPath: +# readOnly: true|false +# mountPropagation: None|HostToContainer|Bidirectional + +## Additional InitContainers to initialize the pod +## +extraInitContainers: [] + +## Liveness probe +## +livenessProbe: + failureThreshold: 3 + httpGet: + httpHeaders: [] + scheme: http + initialDelaySeconds: 0 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + +## Readiness probe +## +readinessProbe: + failureThreshold: 3 + httpGet: + httpHeaders: [] + scheme: http + initialDelaySeconds: 0 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + +# Enable vertical pod autoscaler support for prometheus-node-exporter +verticalPodAutoscaler: + enabled: false + + # Recommender responsible for generating recommendation for the object. + # List should be empty (then the default recommender will generate the recommendation) + # or contain exactly one recommender. + # recommenders: + # - name: custom-recommender-performance + + # List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory + controlledResources: [] + # Specifies which resource values should be controlled: RequestsOnly or RequestsAndLimits. + # controlledValues: RequestsAndLimits + + # Define the max allowed resources for the pod + maxAllowed: {} + # cpu: 200m + # memory: 100Mi + # Define the min allowed resources for the pod + minAllowed: {} + # cpu: 200m + # memory: 100Mi + + # updatePolicy: + # Specifies minimal number of replicas which need to be alive for VPA Updater to attempt pod eviction + # minReplicas: 1 + # Specifies whether recommended updates are applied when a Pod is started and whether recommended updates + # are applied during the life of a Pod. Possible values are "Off", "Initial", "Recreate", and "Auto". + # updateMode: Auto + +# Extra manifests to deploy as an array +extraManifests: [] + # - | + # apiVersion: v1 + # kind: ConfigMap + # metadata: + # name: prometheus-extra + # data: + # extra-data: "value" + +# Override version of app, required if image.tag is defined and does not follow semver +version: "" diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/Chart.yaml new file mode 100644 index 0000000000..babbb13b95 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rke2ControllerManager +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2ControllerManager/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/Chart.yaml new file mode 100644 index 0000000000..4453ba26e7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rke2Etcd +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Etcd/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/Chart.yaml new file mode 100644 index 0000000000..aa61f8b60c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rke2IngressNginx +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2IngressNginx/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/Chart.yaml new file mode 100644 index 0000000000..a9dfd1ed18 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rke2Proxy +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Proxy/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/Chart.yaml new file mode 100644 index 0000000000..4dcfec6537 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rke2Scheduler +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rke2Scheduler/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/Chart.yaml new file mode 100644 index 0000000000..2dceb6a1fe --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rkeControllerManager +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeControllerManager/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/Chart.yaml new file mode 100644 index 0000000000..5e05a16eec --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rkeEtcd +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeEtcd/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/Chart.yaml new file mode 100644 index 0000000000..96a8cc7ea8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rkeIngressNginx +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeIngressNginx/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/Chart.yaml new file mode 100644 index 0000000000..13c08619c3 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rkeProxy +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeProxy/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/.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/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/Chart.yaml new file mode 100644 index 0000000000..7e202304af --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/Chart.yaml @@ -0,0 +1,15 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: linux + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-pushprox +apiVersion: v1 +appVersion: v0.1.4-rancher2 +description: Sets up a deployment of the PushProx proxy and a DaemonSet of PushProx + clients. +kubeVersion: '>=1.28.0-0' +name: rkeScheduler +type: application +version: 0.2.0 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/README.md new file mode 100644 index 0000000000..345002f48a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/README.md @@ -0,0 +1,90 @@ +# rancher-pushprox + +A Rancher chart based on Rancher [PushProx](https://github.com/rancher/PushProx) that sets up a Deployment of a PushProx proxy and a DaemonSet of PushProx clients on a Kubernetes cluster. + +Installs [rancher-pushprox](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-pushprox) to create PushProx clients that can access their host's network and register with a PushProx proxy. A [Prometheus Operator](https://github.com/coreos/prometheus-operator) ServiceMonitor CR is also included that is configured to scrape the metrics from each of the clients through the proxy. + +Using an instance of this chart is suitable for the following scenarios: +- You need to scrape metrics from a port that should not be accessible outside of the host (e.g. scraping `etcd` metrics in a hardened cluster) +- You need to scrape metrics on a host that are not exposed outside of 127.0.0.1 (e.g. scraping `kube-proxy` metrics) +- You need to scrape metrics through HTTPS using certs hosted directly on `hostPath` +- You need to scrape metrics from Kubernetes components that require authorization via a service account (e.g. permissions to make request to `/metrics`) +- You need to scrape metrics without access to cacerts (i.e. enable `insecureSkipVerify`) + +The clients and proxy are created based on a Rancher fork of the [prometheus-community/PushProx](https://github.com/prometheus-community/PushProx) project. + +## Upgrading to Kubernetes v1.25+ + +Starting in Kubernetes v1.25, [Pod Security Policies](https://kubernetes.io/docs/concepts/security/pod-security-policy/) have been removed from the Kubernetes API. + +As a result, **before upgrading to Kubernetes v1.25** (or on a fresh install in a Kubernetes v1.25+ cluster), users are expected to perform an in-place upgrade of this chart with `global.cattle.psp.enabled` set to `false` if it has been previously set to `true`. +​ +> **Note:** +> In this chart release, any previous field that was associated with any PSP resources have been removed in favor of a single global field: `global.cattle.psp.enabled`. + +> **Note:** +> If you upgrade your cluster to Kubernetes v1.25+ before removing PSPs via a `helm upgrade` (even if you manually clean up resources), **it will leave the Helm release in a broken state within the cluster such that further Helm operations will not work (`helm uninstall`, `helm upgrade`, etc.).** +> +> If your charts get stuck in this state, please consult the Rancher docs on how to clean up your Helm release secrets. + +Upon setting `global.cattle.psp.enabled` to false, the chart will remove any PSP resources deployed on its behalf from the cluster. This is the default setting for this chart. + +As a replacement for PSPs, [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) should be used. Please consult the Rancher docs for more details on how to configure your chart release namespaces to work with the new Pod Security Admission and apply Pod Security Standards. + +## Configuration + +The following tables list the configurable parameters of the rancher-pushprox chart and their default values. + +### General + +#### Required +| Parameter | Description | Example | +| ----- | ----------- | ------ | +| `component` | The component that is being monitored | `kube-etcd` +| `metricsPort` | The port on the host that contains the metrics you want to scrape (e.g. `http://:/metrics`) | `2379` | +| `namespaceOverride` | The namespace to install the chart | `""` + +#### Optional +| Parameter | Description | Default | +| ----- | ----------- | ------ | +| `serviceMonitor.enabled` | Deploys a [Prometheus Operator](https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#servicemonitor) ServiceMonitor CR that is configured to scrape metrics on the hosts that the clients are deployed on via the proxy. Also deploys a Service that points to all pods with the expected client name that exposes the `metricsPort` selected | `true` | +| `serviceMonitor.endpoints` | A list of endpoints that will be added to the ServiceMonitor based on the [Endpoint spec](https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint) | `[{port: metrics}]` | +| `service.selector` | The selector that is used to populate the Service's Endpoints object. The chart will error out on rendering templating if `.Values.clients.enabled` is set alongside this field, since it is expected that this service should point to the PushProx Clients Daemonset / Deployment | `{}` | +| `clients.enabled` | Deploys a DaemonSet of clients that are each capable of scraping endpoints on the hostNetwork it is deployed on | `true` | +| `clients.port` | The port where the client will publish PushProx client-specific metrics. If deploying multiple clients onto the same node, the clients should not have conflicting ports | `9369` | +| `clients.proxyUrl` | Overrides the default proxyUrl setting of `http://pushprox-{{ .Values.component }}-proxy.{{ . Release.Namespace }}.svc.cluster.local:{{ .Values.proxy.port }}"` with the `proxyUrl` specified | `""` | +| `clients.useLocalhost` | Sets a flag on each client deployment to redirect scrapes directed to `HOST_IP` to `127.0.0.1` | `false` | +| `clients.https.enabled` | Enables scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.forceHTTPSScheme` | Forces scraping metrics via HTTPS using the provided TLS certs that exist on each host | `false` | +| `clients.https.useServiceAccountCredentials` | If set to true, the client will create a service account with permissions to scrape `/metrics` endpoint of Kubernetes components. The client will use the service account token provided to make authorized scrape requests to the Kubernetes API | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.enabled` | If set to true, the client will use service account credentials mounted at the configured path `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath`. This requires permissions to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath` | This is a volume mount on the pod with permissions to scrape `/metrics` endpoint of Kubernetes components | `"/var/run/secrets/kubernetes.io/serviceaccount/token"` | +| `clients.https.authenticationMethod.bearerTokenSecret.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components. This method is deprecated by the prometheus operator and may be removed in a future release | `false` | +| `clients.https.authenticationMethod.authorization.enabled` | If set to true, the client will use service account credentials to scrape `/metrics` endpoint of Kubernetes components | `false` | +| `clients.https.authenticationMethod.authorization.type` | If set, the client will use this type of authorization in its client requests for metrics | `"bearer"` | +| `clients.https.authenticationMethod.authorization.credentials.key` | If set, the client will use this key in the secret created by `clients.https.useServiceAccountCredentials` for authorization in its client requests for metrics | `"token"` | +| `clients.https.authenticationMethod.authorization.credentials.optional` | If set to false, the client will fail if the key in the secret created by `clients.https.useServiceAccountCredentials` does not exist | `false` | +| `clients.https.insecureSkipVerify` | If set to true, the client will disable SSL security checks | `false` | +| `clients.https.certDir` | A `hostPath` where TLS certs can be found. This path is mounted as a volume on an `initContainer` which copies only the necessary files over to an EmptyDir volume used by each client. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.certFile` | The path to the TLS cert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.keyFile` | The path to the TLS key file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.caCertFile` | The path to the TLS cacert file located within `clients.https.certDir`. Required and only used if `clients.https.enabled` is set | `""` | +| `clients.https.seLinuxOptions` | seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. | `""` | +| `clients.metrics.enabled` | Whether the client should publish PushProx client-specific metrics. | `false` | +| `clients.rbac.additionalRules` | Additional permissions to provide to the ServiceAccount bound to the client. This can be used to provide additional permissions for the client to scrape metrics from the k8s API. Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true | `[]` | +| `clients.deployment.enabled` | Deploys the client as a Deployment (generally used if the underlying hostNetwork Pod that is being scraped is managed by a Deployment) | `false` | +| `clients.deployment.replicas` | The number of pods the Deployment has, it should match the number of pod the hostNetwork Deployment has. Required and only used if `client.deployment.enable` is set | `0` | +| `clients.deployment.affinity` | The affinity rules that allocate the pod to the node in which the hostNetwork Deployment's pods run. Required and only used if `client.deployment.enable` is set | `{}` | +| `clients.resources` | Set resource limits and requests for the client container | `{}` | +| `clients.nodeSelector` | Select which nodes to deploy the clients on | `{}` | +| `clients.tolerations` | Specify tolerations for clients | `[]` | +| `proxy.enabled` | Deploys the proxy that each client will register with | `true` | +| `proxy.port` | The port exposed by the proxy that each client will register with to allow metrics to be scraped from the host | `8080` | +| `proxy.resources` | Set resource limits and requests for the proxy container | `{}` | +| `proxy.nodeSelector` | Select which nodes the proxy can be deployed on | `{}` | +| `proxy.tolerations` | Specify tolerations (if necessary) to allow the proxy to be deployed on the selected node | `[]` | +| `kubeVersionOverrides` | A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches any of the semver constraints provided as keys on the map. On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. | `[]` + +*Tip: The filepaths set in `clients.https.File` can include wildcard characters*. + +See [rancher-monitoring](https://github.com/rancher/charts/tree/gh-pages/packages/rancher-monitoring) for examples of how this chart can be used. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/_helpers.tpl new file mode 100644 index 0000000000..1ba5093944 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/_helpers.tpl @@ -0,0 +1,170 @@ +# Rancher + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# General + +{{- define "applyKubeVersionOverrides" -}} +{{- $overrides := dict -}} +{{- range $override := .Values.kubeVersionOverrides -}} +{{- if semverCompare $override.constraint $.Capabilities.KubeVersion.Version -}} +{{- $_ := mergeOverwrite $overrides $override.values -}} +{{- end -}} +{{- end -}} +{{- $_ := mergeOverwrite .Values $overrides -}} +{{- end -}} + +{{- define "pushprox.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{- define "pushProxy.commonLabels" -}} +release: {{ .Release.Name }} +component: {{ .Values.component | quote }} +provider: kubernetes +{{- end -}} + +{{- define "pushProxy.proxyUrl" -}} +{{- $_ := (required "Template requires either .Values.proxy.port or .Values.client.proxyUrl to set proxyUrl for client" (or .Values.clients.proxyUrl .Values.proxy.port)) -}} +{{- if .Values.clients.proxyUrl -}} +{{ printf "%s" .Values.clients.proxyUrl }} +{{- else -}} +{{ printf "http://%s.%s.svc:%d" (include "pushProxy.proxy.name" .) (include "pushprox.namespace" .) (int .Values.proxy.port) }} +{{- end -}}{{- end -}} + +# Client + +{{- define "pushProxy.client.name" -}} +{{- printf "pushprox-%s-client" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.serviceAccountTokenName" -}} +{{- printf "pushprox-%s-client-service-account-token" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.client.labels" -}} +k8s-app: {{ template "pushProxy.client.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# Proxy + +{{- define "pushProxy.proxy.name" -}} +{{- printf "pushprox-%s-proxy" (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.proxy.labels" -}} +k8s-app: {{ template "pushProxy.proxy.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +# ServiceMonitor + +{{- define "pushprox.serviceMonitor.name" -}} +{{- printf "%s-%s" .Release.Name (required ".Values.component is required" .Values.component) -}} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.labels" -}} +app: {{ template "pushprox.serviceMonitor.name" . }} +{{ template "pushProxy.commonLabels" . }} +{{- end -}} + +{{- define "pushProxy.serviceMonitor.endpoints" -}} +{{- $proxyURL := (include "pushProxy.proxyUrl" .) -}} +{{- $useHTTPS := .Values.clients.https.enabled -}} +{{- $setHTTPSScheme := .Values.clients.https.forceHTTPSScheme -}} +{{- $insecureSkipVerify := .Values.clients.https.insecureSkipVerify -}} +{{- $useServiceAccountCredentials := .Values.clients.https.useServiceAccountCredentials -}} +{{- $serviceAccountTokenName := (include "pushProxy.client.serviceAccountTokenName" . ) -}} +{{- $metricRelabelings := list }} +{{- $endpoints := .Values.serviceMonitor.endpoints }} +{{- if .Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- range $endpoints }} +{{- if $.Values.proxy.enabled }} +{{- $_ := set . "proxyUrl" $proxyURL }} +{{- end }} +{{- $clusterIdRelabel := dict }} +{{- $metricRelabelings := list }} +{{- if $.Values.global.cattle.clusterId }} +{{- $_ := set $clusterIdRelabel "action" "replace" }} +{{- $_ := set $clusterIdRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterIdRelabel "targetLabel" "cluster_id" }} +{{- $_ := set $clusterIdRelabel "replacement" $.Values.global.cattle.clusterId }} +{{- $metricRelabelings = append $metricRelabelings $clusterIdRelabel }} +{{- end }} +{{- $clusterNameRelabel := dict }} +{{- if $.Values.global.cattle.clusterName }} +{{- $_ := set $clusterNameRelabel "action" "replace" }} +{{- $_ := set $clusterNameRelabel "sourceLabels" (list "__address__") }} +{{- $_ := set $clusterNameRelabel "targetLabel" "cluster_name" }} +{{- $_ := set $clusterNameRelabel "replacement" $.Values.global.cattle.clusterName }} +{{- $metricRelabelings = append $metricRelabelings $clusterNameRelabel }} +{{- end }} +{{- if not (empty $metricRelabelings) }} +{{- $_ := set . "metricRelabelings" ($metricRelabelings)}} +{{- end }} +{{- if $setHTTPSScheme -}} +{{- $_ := set . "scheme" "https" }} +{{- end -}} +{{- if $useHTTPS -}} +{{- if (hasKey . "params") }} +{{- $_ := set (get . "params") "_scheme" (list "https") }} +{{- else }} +{{- $_ := set . "params" (dict "_scheme" (list "https")) }} +{{- end }} +{{- end }} +{{- if (hasKey . "tlsConfig") }} +{{- $_ := set (get . "tlsConfig") "insecureSkipVerify" $insecureSkipVerify }} +{{- else }} +{{- $_ := set . "tlsConfig" (dict "insecureSkipVerify" $insecureSkipVerify) }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenFile.enabled }} +{{- $_ := set . "bearerTokenFile" $.Values.clients.https.authenticationMethod.bearerTokenFile.bearerTokenFilePath }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.bearerTokenSecret.enabled }} +{{- $_ := set . "bearerTokenSecret" $serviceAccountTokenName }} +{{- end }} +{{- if $.Values.clients.https.authenticationMethod.authorization.enabled }} +{{- if (hasKey . "authorization") }} +{{- $_ := set (get . "authorization") "type" $.Values.clients.https.authenticationMethod.authorization.type }} +{{- $_ := set (get . "authorization") "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional) }} +{{- else }} +{{- $_ := set . "authorization" (dict "type" $.Values.clients.https.authenticationMethod.authorization.type) }} +{{- $_ := set . "authorization" (dict "credentials" (dict "name" $serviceAccountTokenName "key" $.Values.clients.https.authenticationMethod.authorization.credentials.key "optional" $.Values.clients.https.authenticationMethod.authorization.credentials.optional)) }} +{{- end }} +{{- end }} +{{- end }} +{{- toYaml $endpoints }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-clients-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-clients-rbac.yaml new file mode 100644 index 0000000000..a8e27c3735 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-clients-rbac.yaml @@ -0,0 +1,97 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.client.name" . }} +{{- end }} +{{- if and .Values.clients.https.enabled .Values.clients.https.useServiceAccountCredentials }} +- nonResourceURLs: ["/metrics"] + verbs: ["get"] +{{- if .Values.clients.rbac.additionalRules }} +{{ toYaml .Values.clients.rbac.additionalRules }} +{{- end }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.client.name" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.client.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +--- +{{- if .Values.clients.https.useServiceAccountCredentials }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/service-account-token +metadata: + name: {{ template "pushProxy.client.serviceAccountTokenName" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + annotations: + kubernetes.io/service-account.name: {{ template "pushProxy.client.name" . }} +{{- end }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: true + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 6 }} +{{- end }} + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 0 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + - 'emptyDir' + - 'hostPath' + allowedHostPaths: + - pathPrefix: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + readOnly: true +{{- end }} +{{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-clients.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-clients.yaml new file mode 100644 index 0000000000..e8fcfb3883 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-clients.yaml @@ -0,0 +1,157 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.clients }}{{- if .Values.clients.enabled }} +apiVersion: apps/v1 +{{- if .Values.clients.deployment.enabled }} +kind: Deployment +{{- else }} +kind: DaemonSet +{{- end }} +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} + pushprox-exporter: "client" +spec: + {{- if .Values.clients.deployment.enabled }} + replicas: {{ .Values.clients.deployment.replicas }} + {{- end }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.client.labels" . | nindent 8 }} + spec: + {{- if .Values.clients.affinity }} + affinity: {{ toYaml .Values.clients.affinity | nindent 8 }} + {{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.clients.nodeSelector }} +{{ toYaml .Values.clients.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.clients.tolerations }} +{{ toYaml .Values.clients.tolerations | indent 8 }} +{{- end }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + serviceAccountName: {{ template "pushProxy.client.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-client + image: {{ template "system_default_registry" . }}{{ .Values.clients.image.repository }}:{{ .Values.clients.image.tag }} + command: + {{- range .Values.clients.command }} + - {{ . | quote }} + {{- end }} + args: + - --fqdn=$(HOST_IP) + - --proxy-url=$(PROXY_URL) + {{- if .Values.clients.metrics.enabled }} + - --metrics-addr=$(PORT) + {{- end }} + - --allow-port={{ required "Need .Values.metricsPort to configure client to be allowed to scrape metrics at port" .Values.metricsPort}} + {{- if .Values.clients.useLocalhost }} + - --use-localhost + {{- end }} + {{- if .Values.clients.https.enabled }} + {{- if .Values.clients.https.insecureSkipVerify }} + - --insecure-skip-verify + {{- end }} + {{- if .Values.clients.https.useServiceAccountCredentials }} + - --token-path=/var/run/secrets/kubernetes.io/serviceaccount/token + {{- end }} + {{- if .Values.clients.https.certDir }} + - --tls.cert=/etc/ssl/push-proxy/push-proxy.pem + - --tls.key=/etc/ssl/push-proxy/push-proxy-key.pem + - --tls.cacert=/etc/ssl/push-proxy/push-proxy-ca-cert.pem + {{- end }} + {{- end }} + env: + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- if .Values.clients.metrics.enabled }} + - name: PORT + value: :{{ .Values.clients.port }} + {{- end }} + - name: PROXY_URL + value: {{ template "pushProxy.proxyUrl" . }} + securityContext: + runAsNonRoot: true + runAsUser: 1000 + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + volumeMounts: + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + {{- end }} + {{- if .Values.clients.resources }} + resources: {{ toYaml .Values.clients.resources | nindent 10 }} + {{- end }} + {{- if and .Values.clients.https.enabled .Values.clients.https.certDir }} + initContainers: + - name: copy-certs + image: {{ template "system_default_registry" . }}{{ .Values.clients.copyCertsImage.repository }}:{{ .Values.clients.copyCertsImage.tag }} + command: + - sh + - -c + - | + echo "Searching for files to copy within the source volume" + echo "cert: ${CERT_FILE_NAME}" + echo "key: ${KEY_FILE_NAME}" + echo "cacert: ${CACERT_FILE_NAME}" + + CERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CERT_FILE_NAME}" | sort -r | head -n 1) + KEY_FILE_SOURCE=$(find /etc/source/ -type f -name "${KEY_FILE_NAME}" | sort -r | head -n 1) + CACERT_FILE_SOURCE=$(find /etc/source/ -type f -name "${CACERT_FILE_NAME}" | sort -r | head -n 1) + + test -z ${CERT_FILE_SOURCE} && echo "Failed to find cert file" && exit 1 + test -z ${KEY_FILE_SOURCE} && echo "Failed to find key file" && exit 1 + test -z ${CACERT_FILE_SOURCE} && echo "Failed to find cacert file" && exit 1 + + echo "Copying cert file from $CERT_FILE_SOURCE to $CERT_FILE_TARGET" + cp $CERT_FILE_SOURCE $CERT_FILE_TARGET || exit 1 + chmod 444 $CERT_FILE_TARGET || exit 1 + + echo "Copying key file from $KEY_FILE_SOURCE to $KEY_FILE_TARGET" + cp $KEY_FILE_SOURCE $KEY_FILE_TARGET || exit 1 + chmod 444 $KEY_FILE_TARGET || exit 1 + + echo "Copying cacert file from $CACERT_FILE_SOURCE to $CACERT_FILE_TARGET" + cp $CACERT_FILE_SOURCE $CACERT_FILE_TARGET || exit 1 + chmod 444 $CACERT_FILE_TARGET || exit 1 + env: + - name: CERT_FILE_NAME + value: {{ required "Need a TLS cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.certFile }} + - name: KEY_FILE_NAME + value: {{ required "Need a TLS key file for scraping metrics endpoint over HTTPs" .Values.clients.https.keyFile }} + - name: CACERT_FILE_NAME + value: {{ required "Need a TLS CA cert file for scraping metrics endpoint over HTTPs" .Values.clients.https.caCertFile }} + - name: CERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy.pem + - name: KEY_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-key.pem + - name: CACERT_FILE_TARGET + value: /etc/ssl/push-proxy/push-proxy-ca-cert.pem + securityContext: + runAsNonRoot: false +{{- if and .Values.global.seLinux.enabled .Values.clients.https.seLinuxOptions }} + seLinuxOptions: {{ .Values.clients.https.seLinuxOptions | toYaml | nindent 12 }} +{{- end }} + volumeMounts: + - name: metrics-cert-dir-source + mountPath: /etc/source + readOnly: true + - name: metrics-cert-dir + mountPath: /etc/ssl/push-proxy + volumes: + - name: metrics-cert-dir-source + hostPath: + path: {{ required "Need access to volume on host with the SSL cert files to use HTTPs" .Values.clients.https.certDir }} + - name: metrics-cert-dir + emptyDir: {} + {{- end }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-proxy-rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-proxy-rbac.yaml new file mode 100644 index 0000000000..eefe609058 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-proxy-rbac.yaml @@ -0,0 +1,68 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +rules: +{{- if .Values.global.cattle.psp.enabled }} +- apiGroups: ['policy'] + resources: ['podsecuritypolicies'] + verbs: ['use'] + resourceNames: + - {{ template "pushProxy.proxy.name" . }} +{{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "pushProxy.proxy.name" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "pushProxy.proxy.name" . }} +subjects: + - kind: ServiceAccount + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +--- +{{- if .Values.global.cattle.psp.enabled }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ include "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + privileged: false + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'MustRunAsNonRoot' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + - min: 1 + max: 65535 + readOnlyRootFilesystem: false + volumes: + - 'secret' +{{- end }}{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-proxy.yaml new file mode 100644 index 0000000000..723bbd6c00 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-proxy.yaml @@ -0,0 +1,57 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if and .Values.proxy }}{{ if .Values.proxy.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} + pushprox-exporter: "proxy" +spec: + selector: + matchLabels: {{ include "pushProxy.proxy.labels" . | nindent 6 }} + template: + metadata: + labels: {{ include "pushProxy.proxy.labels" . | nindent 8 }} + spec: + securityContext: + runAsNonRoot: true + runAsUser: 1000 + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- if .Values.proxy.nodeSelector }} +{{ toYaml .Values.proxy.nodeSelector | indent 8 }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- if .Values.proxy.tolerations }} +{{ toYaml .Values.proxy.tolerations | indent 8 }} +{{- end }} + serviceAccountName: {{ template "pushProxy.proxy.name" . }} + {{- if .Values.global.imagePullSecretName }} + imagePullSecrets: + - name: {{ .Values.global.imagePullSecretName }} + {{- end }} + containers: + - name: pushprox-proxy + image: {{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }} + command: + {{- range .Values.proxy.command }} + - {{ . | quote }} + {{- end }} + {{- if .Values.proxy.resources }} + resources: {{ toYaml .Values.proxy.resources | nindent 10 }} + {{- end }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.proxy.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +spec: + ports: + - name: pp-proxy + port: {{ required "Need .Values.proxy.port to configure proxy" .Values.proxy.port }} + protocol: TCP + targetPort: {{ .Values.proxy.port }} + selector: {{ include "pushProxy.proxy.labels" . | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-servicemonitor.yaml new file mode 100644 index 0000000000..67eb2216b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/pushprox-servicemonitor.yaml @@ -0,0 +1,45 @@ +{{- template "applyKubeVersionOverrides" . -}} +{{- if .Values.serviceMonitor }}{{- if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "pushprox.serviceMonitor.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.serviceMonitor.labels" . | nindent 4 }} +spec: + endpoints: {{include "pushProxy.serviceMonitor.endpoints" . | nindent 4 }} + jobLabel: component + podTargetLabels: + - component + - pushprox-exporter + namespaceSelector: + matchNames: + - {{ template "pushprox.namespace" . }} + selector: + matchLabels: {{ include "pushProxy.client.labels" . | nindent 6 }} +--- +{{- $selector := "" }} +{{- if not (kindIs "invalid" .Values.service) }} +{{- if not (kindIs "invalid" .Values.service.selector) }} +{{ if .Values.service.selector }} +{{- if .Values.clients.enabled }} +{{- required (printf "Cannot override .Values.service.selector=%s when .Values.clients.enabled=true" (toJson .Values.service.selector)) "" }} +{{- end }} +{{- $selector = (toYaml .Values.service.selector) }} +{{- end }} +{{- end }} +{{- end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "pushProxy.client.name" . }} + namespace: {{ template "pushprox.namespace" . }} + labels: {{ include "pushProxy.client.labels" . | nindent 4 }} +spec: + ports: + - name: metrics + port: {{ required "Need .Values.metricsPort to configure client to listen to metrics at port" .Values.metricsPort}} + protocol: TCP + targetPort: {{ .Values.metricsPort }} + selector: {{ default (include "pushProxy.client.labels" .) $selector | nindent 4 }} +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..16abc2fa83 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/validate-install-crd.yaml @@ -0,0 +1,14 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install Prometheus Operator CRDs before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..a30c59d3b7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/templates/validate-psp-install.yaml @@ -0,0 +1,7 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- if .Values.global.cattle.psp.enabled }} +#{{- if not (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") }} +#{{- fail "The target cluster does not have the PodSecurityPolicy API resource. Please disable PSPs in this chart before proceeding." -}} +#{{- end }} +#{{- end }} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/values.yaml new file mode 100644 index 0000000000..7f38498a1c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/rkeScheduler/values.yaml @@ -0,0 +1,166 @@ +# Default values for rancher-pushprox. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Default image containing both the proxy and the client was generated from the following Dockerfile +# https://github.com/prometheus-community/PushProx/blob/eeadbe766641699129920ccfaaaa30a85c67fe81/Dockerfile#L1-L15 + +# Configuration + +global: + cattle: + psp: + enabled: false + systemDefaultRegistry: "" + seLinux: + enabled: false + +# A list of Semver constraint strings (defined by https://github.com/Masterminds/semver) and values.yaml overrides. +# +# For each key in kubeVersionOverrides, this chart will check to see if the current Kubernetes cluster's version matches +# any of the semver constraints provided as keys on the map. +# +# On seeing a match, the default value for each values.yaml field overridden will be updated with the new value. +# +# If multiple matches are encountered (due to overlapping semver ranges), the matches will be applied in order. +# +# Notes: +# - On running a helm template, Helm generally assumes the kubeVersion is v1.20.0 +# - On running a helm install --dry-run, the correct kubeVersion should be chosen. +kubeVersionOverrides: [] +# - constraint: "< 1.21" +# values: +# metricsPort: 10252 +# clients: +# https: +# enabled: false +# insecureSkipVerify: false +# useServiceAccountCredentials: false + +namespaceOverride: "" + +# The component that is being monitored (i.e. etcd) +component: "component" + +# The port containing the metrics that need to be scraped +metricsPort: 2739 + +# Configure ServiceMonitor that monitors metrics from the metricsPort endpoint +serviceMonitor: + enabled: true + # A list of endpoints that will be added to the ServiceMonitor based on the Endpoint spec + # Source: https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#endpoint + # By default, proxyUrl and params._scheme will be overridden based on other values + endpoints: + - port: metrics + +# Configure Service that grabs scrape targets +service: + # The selector that is used to populate the Service's Endpoints object. + # The chart will error out on rendering templating if .Values.clients.enabled is set alongside this field, + # since it is expected that this service should point to the PushProx Clients Daemonset / Deployment + selector: {} + +clients: + enabled: true + # The port which the PushProx client will post PushProx metrics to + port: 9369 + # If unset, this will default to the URL for the proxy service: http://pushprox-{{component}}-proxy.{{namepsace}}.svc.cluster.local:{{proxy.port}} + # Should be modified if the clients are being deployed outside the cluster where the proxy rests, otherwise leave it null + proxyUrl: "" + # If set to true, the client will forward any requests from the host IP to 127.0.0.1 + # It will only allow proxy requests to the metricsPort specified + useLocalhost: false + # Configuration for accessing metrics via HTTPS + https: + # Does the client require https to access the metrics? + enabled: false + # Does the client require requests be sent to http or https? + forceHTTPSScheme: false + # If set to true, the client will create a service account with adequate permissions and set a flag + # on the client to use the service account token provided by it to make authorized scrape requests + useServiceAccountCredentials: false + # Configuration for authentication to metrics via https endpoint + authenticationMethod: + # Reads token from defined file in container + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenFile: + enabled: false + bearerTokenFilePath: "/var/run/secrets/kubernetes.io/serviceaccount/token" + # Reads token from defined secret in namespace + # This function is deprecated in the prometheus operator api and may be removed in a future version + bearerTokenSecret: + enabled: false + # Reads token from defined secret in namespace + authorization: + enabled: false + type: "bearer" + credentials: + key: "token" + optional: false + # If set to true, the client will disable SSL security checks + insecureSkipVerify: false + # Directory on host where necessary TLS cert and key to scrape metrics can be found + certDir: "" + # Filenames for files located in .Values.clients.https.certDir that correspond to TLS settings + certFile: "" + keyFile: "" + caCertFile: "" + # seLinuxOptions to be passed into the container that copies certs. Should define a container with permissions to read the files in the certDir provided on the host. + # Required and only used if `clients.https.enabled` is set and `clients.https.certDir` is provided. + seLinuxOptions: {} + + metrics: + # Whether the client should publish PushProx client-specific metrics to .Values.clients.port + enabled: false + + rbac: + # Additional permissions to provide to the ServiceAccount bound to the client + # This can be used to provide additional permissions for the client to scrape metrics from the k8s API + # Only enabled if clients.https.enabled and clients.https.useServiceAccountCredentials are true + additionalRules: [] + + # Resource limits + resources: {} + + # Options to select all nodes to deploy client DaemonSet on + nodeSelector: {} + tolerations: [] + affinity: {} + + image: + repository: rancher/pushprox-client + tag: v0.1.4-rancher2-client + command: ["pushprox-client"] + + copyCertsImage: + repository: rancher/mirrored-library-busybox + tag: 1.31.1 + + # The default intention of rancher-pushprox clients is to scrape hostNetwork metrics across all nodes. + # This can be used to scrape internal Kubernetes components or DaemonSets of hostNetwork Pods in + # situations where a cloud provider firewall prevents Pod-To-Host communication but not Pod-To-Pod. + # However, if the underlying hostNetwork Pod that is being scraped is managed by a Deployment, + # this advanced option enables users to deploy the client as a Deployment instead of a DaemonSet. + # If a user deploys this feature and the underlying Deployment's number of replicas changes, the user will + # be responsible for upgrading this chart accordingly to the right number of replicas. + deployment: + enabled: false + replicas: 0 + +proxy: + enabled: true + # The port through which PushProx clients will communicate to the proxy + port: 8080 + + # Resource limits + resources: {} + + # Options to select a node to run a single proxy deployment on + nodeSelector: {} + tolerations: [] + + image: + repository: rancher/pushprox-proxy + tag: v0.1.4-rancher2-proxy + command: ["pushprox-proxy"] diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/.helmignore b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/.helmignore new file mode 100644 index 0000000000..f0c1319444 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/.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/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/Chart.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/Chart.yaml new file mode 100644 index 0000000000..b2fa9e7beb --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/Chart.yaml @@ -0,0 +1,24 @@ +annotations: + catalog.cattle.io/hidden: "true" + catalog.cattle.io/kube-version: '>= 1.28.0-0 < 1.32.0-0' + catalog.cattle.io/os: windows + catalog.rancher.io/certified: rancher + catalog.rancher.io/namespace: cattle-monitoring-system + catalog.rancher.io/release-name: rancher-windows-exporter +apiVersion: v2 +appVersion: 0.25.1 +description: A Helm chart for prometheus windows-exporter +home: https://github.com/prometheus-community/windows_exporter/ +keywords: +- windows-exporter +- windows +- prometheus +- exporter +maintainers: +- email: github@jkroepke.de + name: jkroepke +name: windowsExporter +sources: +- https://github.com/prometheus-community/windows_exporter/ +type: application +version: 0.3.1 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/README.md b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/README.md new file mode 100644 index 0000000000..1da1c64e12 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/README.md @@ -0,0 +1,42 @@ +# Prometheus `Windows Exporter` + +Prometheus exporter for hardware and OS metrics exposed by Windows kernels, written in Go with pluggable metric collectors. + +This chart bootstraps a prometheus [`Windows Exporter`](http://github.com/prometheus-community/windows_exporter) daemonset on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Get Repository Info + +```console +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update +``` + +_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Chart + +```console +helm install [RELEASE_NAME] prometheus-community/prometheus-windows-exporter +``` + +_See [configuration](#configuring) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Uninstall Chart + +```console +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +## Configuring + +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, visit the chart's [values.yaml](./values.yaml), or run these configuration commands: + +```console +helm show values prometheus-community/prometheus-windows-exporter +``` diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/scripts/configure-firewall.ps1 b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/scripts/configure-firewall.ps1 new file mode 100644 index 0000000000..9cbed7112d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/scripts/configure-firewall.ps1 @@ -0,0 +1,31 @@ +$ErrorActionPreference = 'Continue' + +function CheckFirewallRuleError { + # We hit an error. This can happen for a number of reasons, including if the rule already exists + if ($error[0]) { + if (($error[0].Exception.NativeErrorCode) -and ($error[0].Exception.NativeErrorCode.ToString() -eq "AlreadyExists")) { + # Previous versions of monitoring may have already created this Firewall Rule + # Because of this, if the rule alreadys exists there is no need to delete and recreate it. + Write-Host "Detected Existing Firewall Rule, Nothing To Do" + } else { + Write-Host "Error Encountered Setting Up Required Firewall Rule" + $error[0].Exception + exit 1 + } + } +} + +Write-Host "Attempting To Configure Firewall Rules For Ports 9796, 10250" + +# This is the exact same firewall rule that has historically been created by rancher-wins +# https://github.com/rancher/wins/blob/91f670c47f19c6d9fe97d8f66a695d3081ad994f/pkg/apis/process_service_mgmt.go#L149 +New-NetFirewallRule -DisplayName rancher-wins-windows-exporter-TCP-9796 -Name rancher-wins-windows-exporter-TCP-9796 -Action Allow -Protocol TCP -LocalPort 9796 -Enabled True -PolicyStore ActiveStore +CheckFirewallRuleError +Write-Host "Windows Node Exporter Firewall Rule Successfully Created" + +# This rule is required in order to have the Rancher UI display node metrics in the 'Nodes' tab of the cluster explorer +New-NetFirewallRule -DisplayName rancher-wins-windows-exporter-TCP-10250 -Name rancher-wins-windows-exporter-TCP-10250 -Action Allow -Protocol TCP -LocalPort 10250 -Enabled True -PolicyStore ActiveStore +CheckFirewallRuleError +Write-Host "Windows Prometheus Metrics Firewall Rule Successfully Created" + +Write-Host "All Firewall Rules Successfully Configured" diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/_helpers.tpl new file mode 100644 index 0000000000..c9a5d6db8c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/_helpers.tpl @@ -0,0 +1,216 @@ +{{/* +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. +The components in this chart create additional resources that expand the longest created name strings. +The longest name that gets created adds and extra 37 characters, so truncation should be 63-35=26. +*/}} +{{- define "prometheus-windows-exporter.fullname" -}} +{{ printf "%s-windows-exporter" .Release.Name }} +{{- end -}} + +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +{{- define "windowsExporter.renamedMetricsRelabeling" -}} +{{- range $original, $new := (include "windowsExporter.renamedMetrics" . | fromJson) -}} +- sourceLabels: [__name__] + regex: {{ $original }} + replacement: '{{ $new }}' + targetLabel: __name__ +{{ end -}} +{{- end -}} + +{{- define "windowsExporter.labels" -}} +k8s-app: {{ template "prometheus-windows-exporter.fullname" . }} +release: {{ .Release.Name }} +component: "windows-exporter" +provider: kubernetes +{{- end -}} + +{{- define "windowsExporter.renamedMetrics" -}} +{{- $renamed := dict -}} +{{/* v0.15.0 */}} +{{- $_ := set $renamed "windows_mssql_transactions_active_total" "windows_mssql_transactions_active" -}} +{{/* v0.16.0 */}} +{{- $_ := set $renamed "windows_adfs_ad_login_connection_failures" "windows_adfs_ad_login_connection_failures_total" -}} +{{- $_ := set $renamed "windows_adfs_certificate_authentications" "windows_adfs_certificate_authentications_total" -}} +{{- $_ := set $renamed "windows_adfs_device_authentications" "windows_adfs_device_authentications_total" -}} +{{- $_ := set $renamed "windows_adfs_extranet_account_lockouts" "windows_adfs_extranet_account_lockouts_total" -}} +{{- $_ := set $renamed "windows_adfs_federated_authentications" "windows_adfs_federated_authentications_total" -}} +{{- $_ := set $renamed "windows_adfs_passport_authentications" "windows_adfs_passport_authentications_total" -}} +{{- $_ := set $renamed "windows_adfs_password_change_failed" "windows_adfs_password_change_failed_total" -}} +{{- $_ := set $renamed "windows_adfs_password_change_succeeded" "windows_adfs_password_change_succeeded_total" -}} +{{- $_ := set $renamed "windows_adfs_token_requests" "windows_adfs_token_requests_total" -}} +{{- $_ := set $renamed "windows_adfs_windows_integrated_authentications" "windows_adfs_windows_integrated_authentications_total" -}} +{{- $_ := set $renamed "windows_net_packets_outbound_errors" "windows_net_packets_outbound_errors_total" -}} +{{- $_ := set $renamed "windows_net_packets_received_discarded" "windows_net_packets_received_discarded_total" -}} +{{- $_ := set $renamed "windows_net_packets_received_errors" "windows_net_packets_received_errors_total" -}} +{{- $_ := set $renamed "windows_net_packets_received_total" "windows_net_packets_received_total_total" -}} +{{- $_ := set $renamed "windows_net_packets_received_unknown" "windows_net_packets_received_unknown_total" -}} +{{- $_ := set $renamed "windows_dns_memory_used_bytes_total" "windows_dns_memory_used_bytes" -}} +{{- $renamed | toJson -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "prometheus-windows-exporter.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "prometheus-windows-exporter.labels" -}} +helm.sh/chart: {{ include "prometheus-windows-exporter.chart" . }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: metrics +app.kubernetes.io/part-of: {{ include "prometheus-windows-exporter.name" . }} +{{ include "prometheus-windows-exporter.selectorLabels" . }} +{{- with .Chart.AppVersion }} +app.kubernetes.io/version: {{ . | quote }} +{{- end }} +{{- with .Values.podLabels }} +{{ toYaml . }} +{{- end }} +{{- if .Values.releaseLabel }} +release: {{ .Release.Name }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "prometheus-windows-exporter.selectorLabels" -}} +app.kubernetes.io/name: {{ include "prometheus-windows-exporter.fullname" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + + +{{/* +Create the name of the service account to use +*/}} +{{- define "prometheus-windows-exporter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "prometheus-windows-exporter.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +The image to use +*/}} +{{- define "prometheus-windows-exporter.image" -}} +{{- if .Values.image.sha }} +{{- fail "image.sha forbidden. Use image.digest instead" }} +{{- else if .Values.image.digest }} +{{- if .Values.global.cattle.systemDefaultRegistry }} +{{- printf "%s/%s:%s@%s" .Values.global.cattle.systemDefaultRegistry .Values.image.repository (default .Chart.AppVersion .Values.image.tag) .Values.image.digest }} +{{- else }} +{{- printf "%s/%s:%s@%s" .Values.image.registry .Values.image.repository (default .Chart.AppVersion .Values.image.tag) .Values.image.digest }} +{{- end }} +{{- else }} +{{- if .Values.global.cattle.systemDefaultRegistry }} +{{- printf "%s/%s:%s" .Values.global.cattle.systemDefaultRegistry .Values.image.repository (default .Chart.AppVersion .Values.image.tag) }} +{{- else }} +{{- printf "%s/%s:%s" .Values.image.registry .Values.image.repository (default .Chart.AppVersion .Values.image.tag) }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "prometheus-windows-exporter.namespace" -}} +{{- if .Values.namespaceOverride }} +{{- .Values.namespaceOverride }} +{{- else }} +{{- .Release.Namespace }} +{{- end }} +{{- end }} + +{{/* +Create the namespace name of the service monitor +*/}} +{{- define "prometheus-windows-exporter.monitor-namespace" -}} +{{- if .Values.namespaceOverride }} +{{- .Values.namespaceOverride }} +{{- else }} +{{- if .Values.prometheus.monitor.namespace }} +{{- .Values.prometheus.monitor.namespace }} +{{- else }} +{{- .Release.Namespace }} +{{- end }} +{{- end }} +{{- end }} + +{{/* Sets default scrape limits for servicemonitor */}} +{{- define "servicemonitor.scrapeLimits" -}} +{{- with .sampleLimit }} +sampleLimit: {{ . }} +{{- end }} +{{- with .targetLimit }} +targetLimit: {{ . }} +{{- end }} +{{- with .labelLimit }} +labelLimit: {{ . }} +{{- end }} +{{- with .labelNameLengthLimit }} +labelNameLengthLimit: {{ . }} +{{- end }} +{{- with .labelValueLengthLimit }} +labelValueLengthLimit: {{ . }} +{{- end }} +{{- end }} + +{{/* +Formats imagePullSecrets. Input is (dict "Values" .Values "imagePullSecrets" .{specific imagePullSecrets}) +*/}} +{{- define "prometheus-windows-exporter.imagePullSecrets" -}} +{{- range (concat .Values.global.imagePullSecrets .imagePullSecrets) }} + {{- if eq (typeOf .) "map[string]interface {}" }} +- {{ toYaml . | trim }} + {{- else }} +- name: {{ . }} + {{- end }} +{{- end }} +{{- end -}} + +{{/* +Create the namespace name of the pod monitor +*/}} +{{- define "prometheus-windows-exporter.podmonitor-namespace" -}} +{{- if .Values.namespaceOverride }} +{{- .Values.namespaceOverride }} +{{- else }} +{{- if .Values.prometheus.podMonitor.namespace }} +{{- .Values.prometheus.podMonitor.namespace }} +{{- else }} +{{- .Release.Namespace }} +{{- end }} +{{- end }} +{{- end }} + +{{/* Sets default scrape limits for podmonitor */}} +{{- define "podmonitor.scrapeLimits" -}} +{{- with .sampleLimit }} +sampleLimit: {{ . }} +{{- end }} +{{- with .targetLimit }} +targetLimit: {{ . }} +{{- end }} +{{- with .labelLimit }} +labelLimit: {{ . }} +{{- end }} +{{- with .labelNameLengthLimit }} +labelNameLengthLimit: {{ . }} +{{- end }} +{{- with .labelValueLengthLimit }} +labelValueLengthLimit: {{ . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/config.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/config.yaml new file mode 100644 index 0000000000..25f1fa69c2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/config.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "prometheus-windows-exporter.fullname" . }} + namespace: {{ include "prometheus-windows-exporter.namespace" . }} + labels: + {{- include "windowsExporter.labels" $ | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: + config.yml: | + {{- .Values.config | nindent 4 }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/daemonset.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/daemonset.yaml new file mode 100644 index 0000000000..be7feb3ed1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/daemonset.yaml @@ -0,0 +1,200 @@ +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "prometheus-windows-exporter.fullname" . }} + namespace: {{ include "prometheus-windows-exporter.namespace" . }} + labels: + {{- include "windowsExporter.labels" . | nindent 4 }} + {{- with .Values.daemonsetAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "windowsExporter.labels" . | nindent 6 }} + {{- with .Values.updateStrategy }} + updateStrategy: + {{- toYaml . | nindent 4 }} + {{- end }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "windowsExporter.labels" . | nindent 8 }} + spec: + automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + initContainers: + - name: configure-firewall + image: {{ include "prometheus-windows-exporter.image" . }} + command: + - C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe + args: ["-f", "scripts/configure-firewall.ps1"] + volumeMounts: + - mountPath: /scripts + name: exporter-scripts + {{- with .Values.extraInitContainers }} + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "prometheus-windows-exporter.fullname" . }} + containers: + - name: windows-exporter + image: {{ include "prometheus-windows-exporter.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - --config.file=%CONTAINER_SANDBOX_MOUNT_POINT%/config.yml + - --collector.textfile.directories=%CONTAINER_SANDBOX_MOUNT_POINT% + - --web.listen-address=:{{ .Values.service.port }} + {{- with .Values.extraArgs }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + env: + {{- range $key, $value := .Values.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + hostPort: {{ .Values.service.port }} + protocol: TCP + livenessProbe: + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + httpGet: + httpHeaders: + {{- range $_, $header := .Values.livenessProbe.httpGet.httpHeaders }} + - name: {{ $header.name }} + value: {{ $header.value }} + {{- end }} + path: / + port: {{ .Values.service.port }} + scheme: {{ upper .Values.livenessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + readinessProbe: + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + httpGet: + httpHeaders: + {{- range $_, $header := .Values.readinessProbe.httpGet.httpHeaders }} + - name: {{ $header.name }} + value: {{ $header.value }} + {{- end }} + path: / + port: {{ .Values.service.port }} + scheme: {{ upper .Values.readinessProbe.httpGet.scheme }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: config + mountPath: /config.yml + subPath: config.yml + {{- range $_, $mount := .Values.extraHostVolumeMounts }} + - name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + readOnly: {{ $mount.readOnly }} + {{- end }} + {{- range $_, $mount := .Values.sidecarVolumeMount }} + - name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + readOnly: true + {{- end }} + {{- range $_, $mount := .Values.configmaps }} + - name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + {{- end }} + {{- range $_, $mount := .Values.secrets }} + - name: {{ .name }} + mountPath: {{ .mountPath }} + {{- end }} + {{- with .Values.sidecars }} + {{- toYaml . | nindent 8 }} + {{- if or .Values.sidecarVolumeMount .Values.sidecarHostVolumeMounts }} + volumeMounts: + {{- range $_, $mount := .Values.sidecarVolumeMount }} + - name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + readOnly: {{ $mount.readOnly }} + {{- end }} + {{- range $_, $mount := .Values.sidecarHostVolumeMounts }} + - name: {{ $mount.name }} + mountPath: {{ $mount.mountPath }} + readOnly: {{ $mount.readOnly }} + {{- end }} + {{- end }} + {{- end }} + {{- if or .Values.imagePullSecrets .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- include "prometheus-windows-exporter.imagePullSecrets" (dict "Values" .Values "imagePullSecrets" .Values.imagePullSecrets) | indent 8 }} + {{- end }} + hostNetwork: {{ .Values.hostNetwork }} + hostPID: {{ .Values.hostPID }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.dnsConfig }} + dnsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: exporter-scripts + configMap: + name: {{ include "prometheus-windows-exporter.fullname" . }}-scripts + - name: config + configMap: + name: {{ include "prometheus-windows-exporter.fullname" . }} + {{- range $_, $mount := .Values.extraHostVolumeMounts }} + - name: {{ $mount.name }} + hostPath: + path: {{ $mount.hostPath }} + {{- end }} + {{- range $_, $mount := .Values.sidecarVolumeMount }} + - name: {{ $mount.name }} + emptyDir: + medium: Memory + {{- end }} + {{- range $_, $mount := .Values.sidecarHostVolumeMounts }} + - name: {{ $mount.name }} + hostPath: + path: {{ $mount.hostPath }} + {{- end }} + {{- range $_, $mount := .Values.configmaps }} + - name: {{ $mount.name }} + configMap: + name: {{ $mount.name }} + {{- end }} + {{- range $_, $mount := .Values.secrets }} + - name: {{ $mount.name }} + secret: + secretName: {{ $mount.name }} + {{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/podmonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/podmonitor.yaml new file mode 100644 index 0000000000..bbb6c39340 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/podmonitor.yaml @@ -0,0 +1,91 @@ +{{- if .Values.prometheus.podMonitor.enabled }} +apiVersion: {{ .Values.prometheus.podMonitor.apiVersion | default "monitoring.coreos.com/v1" }} +kind: PodMonitor +metadata: + name: {{ include "prometheus-windows-exporter.fullname" . }} + namespace: {{ include "prometheus-windows-exporter.podmonitor-namespace" . }} + labels: + {{- include "windowsExporter.labels" . | nindent 4 }} + {{- with .Values.prometheus.podMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ default "app.kubernetes.io/name" .Values.prometheus.podMonitor.jobLabel }} + {{- include "podmonitor.scrapeLimits" .Values.prometheus.podMonitor | nindent 2 }} + selector: + matchLabels: + {{- with .Values.prometheus.podMonitor.selectorOverride }} + {{- toYaml . | nindent 6 }} + {{- else }} + {{- include "prometheus-windows-exporter.selectorLabels" . | nindent 6 }} + {{- end }} + namespaceSelector: + matchNames: + - {{ include "prometheus-windows-exporter.namespace" . }} + {{- with .Values.prometheus.podMonitor.attachMetadata }} + attachMetadata: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.podTargetLabels }} + podTargetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} + podMetricsEndpoints: + - port: {{ .Values.service.portName }} + {{- with .Values.prometheus.podMonitor.scheme }} + scheme: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.path }} + path: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.basicAuth }} + basicAuth: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.bearerTokenSecret }} + bearerTokenSecret: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.authorization }} + authorization: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.oauth2 }} + oauth2: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.proxyUrl }} + proxyUrl: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.honorTimestamps }} + honorTimestamps: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.honorLabels }} + honorLabels: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + {{- with .Values.prometheus.podMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.podMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 8 }} + {{- end }} + enableHttp2: {{ default false .Values.prometheus.podMonitor.enableHttp2 }} + filterRunning: {{ default true .Values.prometheus.podMonitor.filterRunning }} + followRedirects: {{ default false .Values.prometheus.podMonitor.followRedirects }} + {{- with .Values.prometheus.podMonitor.params }} + params: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/scriptConfig.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/scriptConfig.yaml new file mode 100644 index 0000000000..f514c8161a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/scriptConfig.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "prometheus-windows-exporter.fullname" . }}-scripts + namespace: {{ include "prometheus-windows-exporter.namespace" . }} + labels: + {{- include "windowsExporter.labels" $ | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +data: +{{ (.Files.Glob "scripts/*").AsConfig | indent 2 }} + diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/service.yaml new file mode 100644 index 0000000000..267b796f63 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/service.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "prometheus-windows-exporter.fullname" . }} + namespace: {{ include "prometheus-windows-exporter.namespace" . }} + labels: + {{- include "windowsExporter.labels" $ | nindent 4 }} + {{- if or .Values.prometheus.monitor.enabled .Values.prometheus.podMonitor.enabled }} + {{- with .Values.service.annotations }} + annotations: + {{- unset . "prometheus.io/scrape" | toYaml | nindent 4 }} + {{- end }} + {{- else }} + annotations: + prometheus.io/scrape: "true" + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + {{- if ( and (eq .Values.service.type "NodePort" ) (not (empty .Values.service.nodePort)) ) }} + nodePort: {{ .Values.service.nodePort }} + {{- end }} + targetPort: {{ .Values.service.port }} + protocol: TCP + appProtocol: http + name: {{ .Values.service.portName }} + selector: + {{- include "windowsExporter.labels" . | nindent 4 }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/serviceaccount.yaml new file mode 100644 index 0000000000..14c1c46807 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/serviceaccount.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.rbac.create .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "prometheus-windows-exporter.serviceAccountName" . }} + namespace: {{ include "prometheus-windows-exporter.namespace" . }} + labels: + {{- include "windowsExporter.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- if or .Values.serviceAccount.imagePullSecrets .Values.global.imagePullSecrets }} +imagePullSecrets: + {{- include "prometheus-windows-exporter.imagePullSecrets" (dict "Values" .Values "imagePullSecrets" .Values.serviceAccount.imagePullSecrets) | indent 2 }} +{{- end }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/servicemonitor.yaml new file mode 100644 index 0000000000..2effc07758 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/templates/servicemonitor.yaml @@ -0,0 +1,75 @@ +{{- if .Values.prometheus.monitor.enabled }} +apiVersion: {{ .Values.prometheus.monitor.apiVersion | default "monitoring.coreos.com/v1" }} +kind: ServiceMonitor +metadata: + name: {{ include "prometheus-windows-exporter.fullname" . }} + namespace: {{ include "prometheus-windows-exporter.monitor-namespace" . }} + labels: + {{- include "windowsExporter.labels" . | nindent 4 }} + {{- with .Values.prometheus.monitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + jobLabel: {{ default "app.kubernetes.io/name" .Values.prometheus.monitor.jobLabel }} + {{- include "servicemonitor.scrapeLimits" .Values.prometheus.monitor | nindent 2 }} + {{- with .Values.prometheus.monitor.podTargetLabels }} + podTargetLabels: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- with .Values.prometheus.monitor.selectorOverride }} + {{- toYaml . | nindent 6 }} + {{- else }} + {{- include "windowsExporter.labels" . | nindent 6 }} + {{- end }} + {{- with .Values.prometheus.monitor.attachMetadata }} + attachMetadata: + {{- toYaml . | nindent 4 }} + {{- end }} + endpoints: + - port: {{ .Values.service.portName }} + scheme: {{ .Values.prometheus.monitor.scheme }} + {{- with .Values.prometheus.monitor.basicAuth }} + basicAuth: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.monitor.bearerTokenFile }} + bearerTokenFile: {{ . }} + {{- end }} + {{- with .Values.prometheus.monitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheus.monitor.proxyUrl }} + proxyUrl: {{ . }} + {{- end }} + {{- with .Values.prometheus.monitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.prometheus.monitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + metricRelabelings: +{{- include "windowsExporter.renamedMetricsRelabeling" . | nindent 6 -}} + - sourceLabels: [__name__] + regex: 'wmi_(.*)' + replacement: 'windows_$1' + targetLabel: __name__ + - sourceLabels: [volume, nic] + regex: (.*);(.*) + separator: '' + targetLabel: device + action: replace + replacement: $1$2 + - sourceLabels: [__name__] + regex: windows_cs_logical_processors + replacement: 'system' + targetLabel: mode + relabelings: + - separator: ':' + sourceLabels: + - __meta_kubernetes_pod_host_ip + - __meta_kubernetes_pod_container_port_number + targetLabel: instance +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/values.yaml new file mode 100644 index 0000000000..6f76b5ea93 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/charts/windowsExporter/values.yaml @@ -0,0 +1,367 @@ +# Default values for prometheus-windows-exporter. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + registry: docker.io + repository: rancher/mirrored-prometheus-windows-exporter + # Overrides the image tag whose default is {{ printf "v%s" .Chart.AppVersion }} + os: "windows" + tag: "0.25.1" + pullPolicy: IfNotPresent + digest: "" + +config: |- + collectors: + enabled: '[defaults],tcp,memory,container' + +imagePullSecrets: [] +# - name: "image-pull-secret" +nameOverride: "" +fullnameOverride: "" + +global: + # To help compatibility with other charts which use global.imagePullSecrets. + # Allow either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style). + # global: + # imagePullSecrets: + # - name: pullSecret1 + # - name: pullSecret2 + # or + # global: + # imagePullSecrets: + # - pullSecret1 + # - pullSecret2 + imagePullSecrets: [] + cattle: + systemDefaultRegistry: "" + +service: + type: ClusterIP + port: 9796 + nodePort: + portName: windows-metrics + annotations: {} + +# Additional environment variables that will be passed to the daemonset +env: {} +## env: +## VARIABLE: value + +prometheus: + monitor: + enabled: true + additionalLabels: {} + namespace: "" + + jobLabel: "component" + + # List of pod labels to add to windows exporter metrics + # https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor + podTargetLabels: ["component"] + + scheme: http + basicAuth: {} + bearerTokenFile: + tlsConfig: {} + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## Override serviceMonitor selector + ## + selectorOverride: {} + + ## Attach node metadata to discovered targets. Requires Prometheus v2.35.0 and above. + ## + attachMetadata: + node: false + + relabelings: [] + metricRelabelings: [] + interval: "" + scrapeTimeout: 10s + ## prometheus.monitor.apiVersion ApiVersion for the serviceMonitor Resource(defaults to "monitoring.coreos.com/v1") + apiVersion: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + # PodMonitor defines monitoring for a set of pods. + # ref. https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.PodMonitor + # Using a PodMonitor may be preferred in some environments where there is very large number + # of Windows Exporter endpoints (1000+) behind a single service. + # The PodMonitor is disabled by default. When switching from ServiceMonitor to PodMonitor, + # the time series resulting from the configuration through PodMonitor may have different labels. + # For instance, there will not be the service label any longer which might + # affect PromQL queries selecting that label. + podMonitor: + enabled: false + # Namespace in which to deploy the pod monitor. Defaults to the release namespace. + namespace: "" + # Additional labels, e.g. setting a label for pod monitor selector as set in prometheus + additionalLabels: {} + # release: kube-prometheus-stack + # PodTargetLabels transfers labels of the Kubernetes Pod onto the target. + podTargetLabels: [] + # apiVersion defaults to monitoring.coreos.com/v1. + apiVersion: "" + # Override pod selector to select pod objects. + selectorOverride: {} + # Attach node metadata to discovered targets. Requires Prometheus v2.35.0 and above. + attachMetadata: + node: false + # The label to use to retrieve the job name from. Defaults to label app.kubernetes.io/name. + jobLabel: "" + + # Scheme/protocol to use for scraping. + scheme: "http" + # Path to scrape metrics at. + path: "/metrics" + + # BasicAuth allow an endpoint to authenticate over basic authentication. + # More info: https://prometheus.io/docs/operating/configuration/#endpoint + basicAuth: {} + # Secret to mount to read bearer token for scraping targets. + # The secret needs to be in the same namespace as the pod monitor and accessible by the Prometheus Operator. + # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#secretkeyselector-v1-core + bearerTokenSecret: {} + # TLS configuration to use when scraping the endpoint. + tlsConfig: {} + # Authorization section for this endpoint. + # https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.SafeAuthorization + authorization: {} + # OAuth2 for the URL. Only valid in Prometheus versions 2.27.0 and newer. + # https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.OAuth2 + oauth2: {} + + # ProxyURL eg http://proxyserver:2195. Directs scrapes through proxy to this endpoint. + proxyUrl: "" + # Interval at which endpoints should be scraped. If not specified Prometheus’ global scrape interval is used. + interval: "" + # Timeout after which the scrape is ended. If not specified, the Prometheus global scrape interval is used. + scrapeTimeout: "" + # HonorTimestamps controls whether Prometheus respects the timestamps present in scraped data. + honorTimestamps: true + # HonorLabels chooses the metric’s labels on collisions with target labels. + honorLabels: true + # Whether to enable HTTP2. Default false. + enableHttp2: "" + # Drop pods that are not running. (Failed, Succeeded). + # Enabled by default. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase + filterRunning: "" + # FollowRedirects configures whether scrape requests follow HTTP 3xx redirects. Default false. + followRedirects: "" + # Optional HTTP URL parameters + params: {} + + # RelabelConfigs to apply to samples before scraping. Prometheus Operator automatically adds + # relabelings for a few standard Kubernetes fields. The original scrape job’s name + # is available via the __tmp_prometheus_job_name label. + # More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + relabelings: [] + # MetricRelabelConfigs to apply to samples before ingestion. + metricRelabelings: [] + + # SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + sampleLimit: 0 + # TargetLimit defines a limit on the number of scraped targets that will be accepted. + targetLimit: 0 + # Per-scrape limit on number of labels that will be accepted for a sample. + # Only valid in Prometheus versions 2.27.0 and newer. + labelLimit: 0 + # Per-scrape limit on length of labels name that will be accepted for a sample. + # Only valid in Prometheus versions 2.27.0 and newer. + labelNameLengthLimit: 0 + # Per-scrape limit on length of labels value that will be accepted for a sample. + # Only valid in Prometheus versions 2.27.0 and newer. + labelValueLengthLimit: 0 + +## Customize the updateStrategy if set +updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + +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: 200m + # memory: 50Mi + # requests: + # cpu: 100m +# memory: 30Mi + +serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the fullname template + name: + annotations: {} + imagePullSecrets: [] + automountServiceAccountToken: false + +securityContext: + windowsOptions: + hostProcess: true + runAsUserName: "NT AUTHORITY\\system" + +rbac: + ## If true, create & use RBAC resources + ## + create: true + +# Expose the service to the host network +hostNetwork: true + +# Share the host process ID namespace +hostPID: true + +## Assign a group of affinity scheduling rules +## +affinity: {} +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchFields: +# - key: metadata.name +# operator: In +# values: +# - target-host-name + +# Annotations to be added to windows exporter pods +podAnnotations: + # Fix for very slow GKE cluster upgrades + cluster-autoscaler.kubernetes.io/safe-to-evict: "true" + +# Extra labels to be added to windows exporter pods +podLabels: {} + +# Annotations to be added to windows exporter daemonset +daemonsetAnnotations: {} + +## set to true to add the release label so scraping of the servicemonitor with kube-prometheus-stack works out of the box +releaseLabel: false + +# Custom DNS configuration to be added to prometheus-windows-exporter pods +dnsConfig: {} +# nameservers: +# - 1.2.3.4 +# searches: +# - ns1.svc.cluster-domain.example +# - my.dns.search.suffix +# options: +# - name: ndots +# value: "2" +# - name: edns0 + +## Assign a nodeSelector if operating a hybrid cluster +## +nodeSelector: + kubernetes.io/os: windows + # kubernetes.io/arch: amd64 + +tolerations: + - effect: NoSchedule + operator: Exists + +## Assign a PriorityClassName to pods if set +# priorityClassName: "" + +## Additional container arguments +## +extraArgs: [] +# - --collector.service.services-where +# - "Name LIKE 'sql%'" + +## Additional mounts from the host to windows-exporter container +## +extraHostVolumeMounts: [] +# - name: +# hostPath: +# mountPath: +# readOnly: true|false + +## Additional configmaps to be mounted. +## +configmaps: [] +# - name: +# mountPath: +secrets: [] +# - name: +# mountPath: +## Override the deployment namespace +## +namespaceOverride: "" + +## Additional containers for export metrics to text file +## +sidecars: [] +## - name: nvidia-dcgm-exporter +## image: nvidia/dcgm-exporter:1.4.3 + +## Volume for sidecar containers +## +sidecarVolumeMount: [] +## - name: collector-textfiles +## mountPath: /run/prometheus +## readOnly: false + +## Additional mounts from the host to sidecar containers +## +sidecarHostVolumeMounts: [] +# - name: +# hostPath: +# mountPath: +# readOnly: true|false +# mountPropagation: None|HostToContainer|Bidirectional + +## Additional InitContainers to initialize the pod +## +extraInitContainers: [] + +## Liveness probe +## +livenessProbe: + failureThreshold: 3 + httpGet: + httpHeaders: [] + scheme: http + initialDelaySeconds: 0 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + +## Readiness probe +## +readinessProbe: + failureThreshold: 3 + httpGet: + httpHeaders: [] + scheme: http + initialDelaySeconds: 0 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/ingress-nginx/nginx.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/ingress-nginx/nginx.json new file mode 100644 index 0000000000..565352235a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/ingress-nginx/nginx.json @@ -0,0 +1,1445 @@ +{ + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "$datasource", + "enable": true, + "expr": "sum(changes(nginx_ingress_controller_config_last_reload_successful_timestamp_seconds{instance!=\"unknown\",controller_class=~\"$controller_class\",namespace=~\"$namespace\"}[30s])) by (controller_class)", + "hide": false, + "iconColor": "rgba(255, 96, 96, 1)", + "limit": 100, + "name": "Config Reloads", + "showIn": 0, + "step": "30s", + "tagKeys": "controller_class", + "tags": [], + "titleFormat": "Config Reloaded", + "type": "tags" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "iteration": 1534359654832, + "links": [], + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "$datasource", + "format": "ops", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 20, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "round(sum(irate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\"}[2m])), 0.001)", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Controller Request Volume", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "$datasource", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 82, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(avg_over_time(nginx_ingress_controller_nginx_process_connections{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",state=\"active\"}[2m]))", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Controller Connections", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "$datasource", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 80, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": false + }, + "gridPos": { + "h": 3, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 21, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(rate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\",status!~\"[4-5].*\"}[2m])) / sum(rate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\"}[2m]))", + "format": "time_series", + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "95, 99, 99.5", + "title": "Controller Success Rate (non-4|5xx responses)", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "$datasource", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 18, + "y": 0 + }, + "id": 81, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "avg(irate(nginx_ingress_controller_success{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[1m])) * 60", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Config Reloads", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "total" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "$datasource", + "decimals": 0, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 3, + "x": 21, + "y": 0 + }, + "id": 83, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "count(nginx_ingress_controller_config_last_reload_successful{controller_pod=~\"$controller\",controller_namespace=~\"$namespace\"} == 0)", + "format": "time_series", + "instant": true, + "intervalFactor": 1, + "refId": "A", + "step": 4 + } + ], + "thresholds": "", + "title": "Last Config Failed", + "transparent": false, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 3 + }, + "height": "200px", + "id": 86, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": false, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 300, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "repeatDirection": "h", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "round(sum(irate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (ingress), 0.001)", + "format": "time_series", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ ingress }}", + "metric": "network", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Ingress Request Volume", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "transparent": false, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "max - istio-proxy": "#890f02", + "max - master": "#bf1b00", + "max - prometheus": "#bf1b00" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 2, + "editable": false, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 3 + }, + "id": 87, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": true, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": 300, + "sort": "avg", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\",ingress=~\"$ingress\",status!~\"[4-5].*\"}[2m])) by (ingress) / sum(rate(nginx_ingress_controller_requests{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (ingress)", + "format": "time_series", + "instant": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "{{ ingress }}", + "metric": "container_memory_usage:sort_desc", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Ingress Success Rate (non-4|5xx responses)", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 1, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 2, + "editable": true, + "error": false, + "fill": 1, + "grid": {}, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 10 + }, + "height": "200px", + "id": 32, + "isNew": true, + "legend": { + "alignAsTable": false, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (irate (nginx_ingress_controller_request_size_sum{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[2m]))", + "format": "time_series", + "instant": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "Received", + "metric": "network", + "refId": "A", + "step": 10 + }, + { + "expr": "- sum (irate (nginx_ingress_controller_response_size_sum{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[2m]))", + "format": "time_series", + "hide": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "Sent", + "metric": "network", + "refId": "B", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Network I/O pressure", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "transparent": false, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "max - istio-proxy": "#890f02", + "max - master": "#bf1b00", + "max - prometheus": "#bf1b00" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 2, + "editable": false, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 10 + }, + "id": 77, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": 200, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(nginx_ingress_controller_nginx_process_resident_memory_bytes{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}) ", + "format": "time_series", + "instant": false, + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "nginx", + "metric": "container_memory_usage:sort_desc", + "refId": "A", + "step": 10 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Average Memory Usage", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "max - istio-proxy": "#890f02", + "max - master": "#bf1b00" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 3, + "editable": false, + "error": false, + "fill": 0, + "grid": {}, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 10 + }, + "height": "", + "id": 79, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sort": null, + "sortDesc": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg (rate (nginx_ingress_controller_nginx_process_cpu_seconds_total{controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\"}[2m])) ", + "format": "time_series", + "interval": "10s", + "intervalFactor": 1, + "legendFormat": "nginx", + "metric": "container_cpu", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Average CPU Usage", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "transparent": false, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": "cores", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "columns": [], + "datasource": "$datasource", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 16 + }, + "hideTimeOverride": false, + "id": 75, + "links": [], + "pageSize": 7, + "repeat": null, + "repeatDirection": "h", + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": true + }, + "styles": [ + { + "alias": "Ingress", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "ingress", + "preserveFormat": false, + "sanitize": false, + "thresholds": [], + "type": "string", + "unit": "short" + }, + { + "alias": "Requests", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #A", + "thresholds": [ + "" + ], + "type": "number", + "unit": "ops" + }, + { + "alias": "Errors", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #B", + "thresholds": [], + "type": "number", + "unit": "ops" + }, + { + "alias": "P50 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "link": false, + "pattern": "Value #C", + "thresholds": [], + "type": "number", + "unit": "dtdurations" + }, + { + "alias": "P90 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "pattern": "Value #D", + "thresholds": [], + "type": "number", + "unit": "dtdurations" + }, + { + "alias": "P99 Latency", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "pattern": "Value #E", + "thresholds": [], + "type": "number", + "unit": "dtdurations" + }, + { + "alias": "IN", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Value #F", + "thresholds": [ + "" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "Time", + "thresholds": [], + "type": "hidden", + "unit": "short" + }, + { + "alias": "OUT", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "Value #G", + "thresholds": [], + "type": "number", + "unit": "Bps" + } + ], + "targets": [ + { + "expr": "histogram_quantile(0.50, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le, ingress))", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ ingress }}", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.90, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le, ingress))", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ ingress }}", + "refId": "D" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(nginx_ingress_controller_request_duration_seconds_bucket{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (le, ingress))", + "format": "table", + "hide": false, + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ destination_service }}", + "refId": "E" + }, + { + "expr": "sum(irate(nginx_ingress_controller_request_size_sum{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (ingress)", + "format": "table", + "hide": false, + "instant": true, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ ingress }}", + "refId": "F" + }, + { + "expr": "sum(irate(nginx_ingress_controller_response_size_sum{ingress!=\"\",controller_pod=~\"$controller\",controller_class=~\"$controller_class\",controller_namespace=~\"$namespace\",ingress=~\"$ingress\"}[2m])) by (ingress)", + "format": "table", + "instant": true, + "intervalFactor": 1, + "legendFormat": "{{ ingress }}", + "refId": "G" + } + ], + "timeFrom": null, + "title": "Ingress Percentile Response Times and Transfer Rates", + "transform": "table", + "transparent": false, + "type": "table" + }, + { + "columns": [ + { + "text": "Current", + "value": "current" + } + ], + "datasource": "$datasource", + "fontSize": "100%", + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 24 + }, + "height": "1024", + "id": 85, + "links": [], + "pageSize": 7, + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": false + }, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "TTL", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "pattern": "Current", + "thresholds": [ + "0", + "691200" + ], + "type": "number", + "unit": "s" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "avg(nginx_ingress_controller_ssl_expire_time_seconds{kubernetes_pod_name=~\"$controller\",namespace=~\"$namespace\",ingress=~\"$ingress\"}) by (host) - time()", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{ host }}", + "metric": "gke_letsencrypt_cert_expiration", + "refId": "A", + "step": 1 + } + ], + "title": "Ingress Certificate Expiry", + "transform": "timeseries_aggregations", + "type": "table" + } + ], + "refresh": "5s", + "schemaVersion": 16, + "style": "dark", + "tags": [ + "nginx" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": "label_values(nginx_ingress_controller_config_hash, controller_namespace)", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": "Controller Class", + "multi": false, + "name": "controller_class", + "options": [], + "query": "label_values(nginx_ingress_controller_config_hash{namespace=~\"$namespace\"}, controller_class) ", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": "Controller", + "multi": false, + "name": "controller", + "options": [], + "query": "label_values(nginx_ingress_controller_config_hash{namespace=~\"$namespace\",controller_class=~\"$controller_class\"}, controller_pod) ", + "refresh": 1, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "tags": [], + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": "Ingress", + "multi": false, + "name": "ingress", + "options": [], + "query": "label_values(nginx_ingress_controller_requests{namespace=~\"$namespace\",controller_class=~\"$controller_class\",controller_pod=~\"$controller\"}, ingress) ", + "refresh": 1, + "regex": "", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "2m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "NGINX / Ingress Controller", + "uid": "nginx", + "version": 1 +} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/ingress-nginx/request-handling-performance.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/ingress-nginx/request-handling-performance.json new file mode 100644 index 0000000000..156e33123d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/ingress-nginx/request-handling-performance.json @@ -0,0 +1,963 @@ +{ + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "", + "editable": true, + "gnetId": 9614, + "graphTooltip": 1, + "id": null, + "iteration": 1582146566338, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "Total time taken for nginx and upstream servers to process a request and send a response", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 91, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(\n 0.5,\n sum by (le)(\n rate(\n nginx_ingress_controller_request_duration_seconds_bucket{\n ingress =~ \"$ingress\"\n }[1m]\n )\n )\n)", + "interval": "", + "legendFormat": ".5", + "refId": "D" + }, + { + "expr": "histogram_quantile(\n 0.95,\n sum by (le)(\n rate(\n nginx_ingress_controller_request_duration_seconds_bucket{\n ingress =~ \"$ingress\"\n }[1m]\n )\n )\n)", + "interval": "", + "legendFormat": ".95", + "refId": "B" + }, + { + "expr": "histogram_quantile(\n 0.99,\n sum by (le)(\n rate(\n nginx_ingress_controller_request_duration_seconds_bucket{\n ingress =~ \"$ingress\"\n }[1m]\n )\n )\n)", + "interval": "", + "legendFormat": ".99", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total request handling time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "The time spent on receiving the response from the upstream server", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "hiddenSeries": false, + "id": 94, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(\n 0.5,\n sum by (le)(\n rate(\n nginx_ingress_controller_response_duration_seconds_bucket{\n ingress =~ \"$ingress\"\n }[1m]\n )\n )\n)", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": ".5", + "refId": "D" + }, + { + "expr": "histogram_quantile(\n 0.95,\n sum by (le)(\n rate(\n nginx_ingress_controller_response_duration_seconds_bucket{\n ingress =~ \"$ingress\"\n }[1m]\n )\n )\n)", + "interval": "", + "legendFormat": ".95", + "refId": "B" + }, + { + "expr": "histogram_quantile(\n 0.99,\n sum by (le)(\n rate(\n nginx_ingress_controller_response_duration_seconds_bucket{\n ingress =~ \"$ingress\"\n }[1m]\n )\n )\n)", + "interval": "", + "legendFormat": ".99", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Upstream response time", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "hiddenSeries": false, + "id": 93, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": " sum by (path)(\n rate(\n nginx_ingress_controller_request_duration_seconds_count{\n ingress =~ \"$ingress\"\n }[1m]\n )\n )\n", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ path }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Request volume by Path", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "For each path observed, its median upstream response time", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "hiddenSeries": false, + "id": 98, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(\n .5,\n sum by (le, path)(\n rate(\n nginx_ingress_controller_response_duration_seconds_bucket{\n ingress =~ \"$ingress\"\n }[1m]\n )\n )\n)", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ path }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Median upstream response time by Path", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "Percentage of 4xx and 5xx responses among all responses.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "hiddenSeries": false, + "id": 100, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (path) (rate(nginx_ingress_controller_request_duration_seconds_count{\n ingress =~ \"$ingress\",\n status =~ \"[4-5].*\"\n}[1m])) / sum by (path) (rate(nginx_ingress_controller_request_duration_seconds_count{\n ingress =~ \"$ingress\",\n}[1m]))", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ path }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Response error rate by Path", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "For each path observed, the sum of upstream request time", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "hiddenSeries": false, + "id": 102, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (path) (rate(nginx_ingress_controller_response_duration_seconds_sum{ingress =~ \"$ingress\"}[1m]))", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ path }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Upstream time consumed by Path", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "hiddenSeries": false, + "id": 101, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": " sum (\n rate(\n nginx_ingress_controller_request_duration_seconds_count{\n ingress =~ \"$ingress\",\n status =~\"[4-5].*\",\n }[1m]\n )\n ) by(path, status)\n", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ path }} {{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Response error volume by Path", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 24 + }, + "hiddenSeries": false, + "id": 99, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (\n rate (\n nginx_ingress_controller_response_size_sum {\n ingress =~ \"$ingress\",\n }[1m]\n )\n) by (path) / sum (\n rate(\n nginx_ingress_controller_response_size_count {\n ingress =~ \"$ingress\",\n }[1m]\n )\n) by (path)\n", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ path }}", + "refId": "D" + }, + { + "expr": " sum (rate(nginx_ingress_controller_response_size_bucket{\n ingress =~ \"$ingress\",\n }[1m])) by (le)\n", + "hide": true, + "legendFormat": "{{le}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average response size by Path", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 32 + }, + "hiddenSeries": false, + "id": 96, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum (\n rate(\n nginx_ingress_controller_ingress_upstream_latency_seconds_sum {\n ingress =~ \"$ingress\",\n }[1m]\n)) / sum (\n rate(\n nginx_ingress_controller_ingress_upstream_latency_seconds_count {\n ingress =~ \"$ingress\",\n }[1m]\n )\n)\n", + "hide": false, + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "average", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Upstream service latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "30s", + "schemaVersion": 22, + "style": "dark", + "tags": [ + "nginx" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".*", + "current": {}, + "datasource": "$datasource", + "definition": "label_values(nginx_ingress_controller_requests, ingress) ", + "hide": 0, + "includeAll": true, + "label": "Service Ingress", + "multi": false, + "name": "ingress", + "options": [], + "query": "label_values(nginx_ingress_controller_requests, ingress) ", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "2m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "NGINX / Request Handling Performance", + "uid": "4GFbkOsZk", + "version": 1 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/cluster/rancher-cluster-nodes.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/cluster/rancher-cluster-nodes.json new file mode 100644 index 0000000000..d1cc3b70ac --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/cluster/rancher-cluster-nodes.json @@ -0,0 +1,793 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 28, + "links": [], + "panels": [ + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - avg(irate({__name__=~\"node_cpu_seconds_total|windows_cpu_time_total\",mode=\"idle\"}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "{{instance}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Load[5m] ({{instance}})" + }, + "properties": [] + } + ] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_load1 OR avg_over_time(windows_system_processor_queue_length[1m])) by (instance)", + "interval": "", + "legendFormat": "Load[1m] ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(node_load5 OR avg_over_time(windows_system_processor_queue_length[5m])) by (instance)", + "interval": "", + "legendFormat": "Load[5m] ({{instance}})", + "refId": "B" + }, + { + "expr": "sum(node_load15 OR avg_over_time(windows_system_processor_queue_length[15m])) by (instance)", + "interval": "", + "legendFormat": "Load[15m] ({{instance}})", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Load Average", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - sum(node_memory_MemAvailable_bytes OR windows_os_physical_memory_free_bytes) by (instance) / sum(node_memory_MemTotal_bytes OR windows_cs_physical_memory_bytes) by (instance) ", + "interval": "", + "legendFormat": "{{instance}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - (sum(node_filesystem_free_bytes{device!~\"rootfs|HarddiskVolume.+\"} OR windows_logical_disk_free_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) by (instance) / sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\"} OR windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) by (instance))", + "interval": "", + "legendFormat": "{{instance}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_disk_read_bytes_total[$__rate_interval]) OR rate(windows_logical_disk_read_bytes_total[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Read ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(rate(node_disk_written_bytes_total[$__rate_interval]) OR rate(windows_logical_disk_write_bytes_total[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Write ({{instance}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 7 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_network_receive_errs_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) by (instance) OR sum(rate(windows_net_packets_received_errors_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Receive Errors ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(rate(node_network_receive_packets_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) by (instance) OR sum(rate(windows_net_packets_received_total_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Receive Total ({{instance}})", + "refId": "B" + }, + { + "expr": "sum(rate(node_network_transmit_errs_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) by (instance) OR sum(rate(windows_net_packets_outbound_errors_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Transmit Errors ({{instance}})", + "refId": "C" + }, + { + "expr": "sum(rate(node_network_receive_drop_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) by (instance) OR sum(rate(windows_net_packets_received_discarded_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Receive Dropped ({{instance}})", + "refId": "D" + }, + { + "expr": "sum(rate(node_network_transmit_drop_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) by (instance) OR sum(rate(windows_net_packets_outbound_discarded{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Transmit Dropped ({{instance}})", + "refId": "E" + }, + { + "expr": "sum(rate(node_network_transmit_packets_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) by (instance) OR sum(rate(windows_net_packets_sent_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Transmit Total ({{instance}})", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_network_transmit_bytes_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval]) OR rate(windows_net_packets_sent_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Transmit Total ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(rate(node_network_receive_bytes_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval]) OR rate(windows_net_packets_received_total_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Receive Total ({{instance}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Cluster (Nodes)", + "uid": "rancher-cluster-nodes-1", + "version": 3 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/cluster/rancher-cluster.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/cluster/rancher-cluster.json new file mode 100644 index 0000000000..ec977f55d1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/cluster/rancher-cluster.json @@ -0,0 +1,776 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 28, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - avg(irate({__name__=~\"node_cpu_seconds_total|windows_cpu_time_total\",mode=\"idle\"}[$__rate_interval]))", + "legendFormat": "Total", + "interval": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Load[5m]" + }, + "properties": [] + } + ] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_load1 OR avg_over_time(windows_system_processor_queue_length[1m]))", + "interval": "", + "legendFormat": "Load[1m]", + "refId": "A" + }, + { + "expr": "sum(node_load5 OR avg_over_time(windows_system_processor_queue_length[5m]))", + "interval": "", + "legendFormat": "Load[5m]", + "refId": "B" + }, + { + "expr": "sum(node_load15 OR avg_over_time(windows_system_processor_queue_length[15m]))", + "interval": "", + "legendFormat": "Load[15m]", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Load Average", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - sum(node_memory_MemAvailable_bytes OR windows_os_physical_memory_free_bytes) / sum(node_memory_MemTotal_bytes OR windows_cs_physical_memory_bytes)", + "legendFormat": "Total", + "interval": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - (sum(node_filesystem_free_bytes{device!~\"rootfs|HarddiskVolume.+\"} OR windows_logical_disk_free_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) / sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\"} OR windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}))", + "legendFormat": "Total", + "interval": "", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_disk_read_bytes_total[$__rate_interval]) OR rate(windows_logical_disk_read_bytes_total[$__rate_interval]))", + "interval": "", + "legendFormat": "Read", + "refId": "A" + }, + { + "expr": "sum(rate(node_disk_written_bytes_total[$__rate_interval]) OR rate(windows_logical_disk_write_bytes_total[$__rate_interval]))", + "interval": "", + "legendFormat": "Write", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 7 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(rate(node_network_receive_errs_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_received_errors_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Receive Errors", + "refId": "A" + }, + { + "expr": "(sum(rate(node_network_receive_packets_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_received_total_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Receive Total", + "refId": "B" + }, + { + "expr": "(sum(rate(node_network_transmit_errs_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_outbound_errors_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Transmit Errors", + "refId": "C" + }, + { + "expr": "(sum(rate(node_network_receive_drop_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_received_discarded_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Receive Dropped", + "refId": "D" + }, + { + "expr": "(sum(rate(node_network_transmit_drop_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_outbound_discarded{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Transmit Dropped", + "refId": "E" + }, + { + "expr": "(sum(rate(node_network_transmit_packets_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_sent_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Transmit Total", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_network_transmit_bytes_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval]) OR rate(windows_net_packets_sent_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval]))", + "interval": "", + "legendFormat": "Transmit Total", + "refId": "A" + }, + { + "expr": "sum(rate(node_network_receive_bytes_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\"}[$__rate_interval]) OR rate(windows_net_packets_received_total_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*'}[$__rate_interval]))", + "interval": "", + "legendFormat": "Receive Total", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Cluster", + "uid": "rancher-cluster-1", + "version": 3 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/bundle.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/bundle.json new file mode 100644 index 0000000000..698f48aeed --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/bundle.json @@ -0,0 +1,246 @@ +{ + "description": "Bundle", + "graphTooltip": 1, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 0 + }, + "id": 1, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_ready{exported_namespace=\"$namespace\",name=~\"$name\"}) / sum(fleet_bundle_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Bundles", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 0 + }, + "id": 2, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_not_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_out_of_sync{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Out of Sync" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_err_applied{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Err Applied" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_modified{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Modified" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_pending{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Pending" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_wait_applied{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Wait Applied" + } + ], + "title": "Bundles", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 3, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_not_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_out_of_sync{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Out of Sync" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_err_applied{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Err Applied" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_modified{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Modified" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_pending{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Pending" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundle_wait_applied{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Wait Applied" + } + ], + "title": "Bundles", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "templating": { + "list": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "name": "namespace", + "query": "label_values(fleet_bundle_desired_ready, exported_namespace)", + "refresh": 2, + "type": "query" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "includeAll": true, + "name": "name", + "query": "label_values(fleet_bundle_desired_ready{exported_namespace=~\"$namespace\"}, name)", + "refresh": 2, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timezone": "utc", + "title": "Fleet / Bundle", + "uid": "fleet-bundle" +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/bundledeployment.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/bundledeployment.json new file mode 100644 index 0000000000..c81f7a6212 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/bundledeployment.json @@ -0,0 +1,219 @@ +{ + "description": "BundleDeployment", + "graphTooltip": 1, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 0 + }, + "id": 1, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"Ready\"}) / sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\"})" + } + ], + "title": "Ready BundleDeployments", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 0 + }, + "id": 2, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"Ready\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"NotReady\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"WaitApplied\"})", + "legendFormat": "Wait Applied" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"ErrApplied\"})", + "legendFormat": "Err Applied" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"OutOfSync\"})", + "legendFormat": "OutOfSync" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"Pending\"})", + "legendFormat": "Pending" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"Modified\"})", + "legendFormat": "Modified" + } + ], + "title": "BundleDeployments", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 3, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"Ready\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"NotReady\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"WaitApplied\"})", + "legendFormat": "Wait Applied" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"ErrApplied\"})", + "legendFormat": "Err Applied" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"OutOfSync\"})", + "legendFormat": "OutOfSync" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"Pending\"})", + "legendFormat": "Pending" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_bundledeployment_state{cluster_namespace=~\"$namespace\",state=\"Modified\"})", + "legendFormat": "Modified" + } + ], + "title": "BundleDeployments", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "templating": { + "list": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "name": "namespace", + "query": "label_values(fleet_bundledeployment_state, cluster_namespace)", + "refresh": 2, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timezone": "utc", + "title": "Fleet / BundleDeployment", + "uid": "fleet-bundledeployment" +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/cluster.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/cluster.json new file mode 100644 index 0000000000..73bdea4834 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/cluster.json @@ -0,0 +1,484 @@ +{ + "description": "Cluster", + "graphTooltip": 1, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 0 + }, + "id": 1, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_ready_git_repos{exported_namespace=\"$namespace\",name=~\"$name\"}) / sum(fleet_cluster_desired_ready_git_repos{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Git Repos", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 0 + }, + "id": 2, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_desired_ready_git_repos{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_ready_git_repos{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + } + ], + "title": "Git Repos", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 3, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_desired_ready_git_repos{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_ready_git_repos{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + } + ], + "title": "Git Repos", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 13 + }, + "id": 4, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_ready{exported_namespace=\"$namespace\",name=~\"$name\"}) / sum(fleet_cluster_resources_count_desiredready{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Resources", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 13 + }, + "id": 5, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_desiredready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_notready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_missing{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Missing" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_modified{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Modified" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_unknown{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Unknown" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_orphaned{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Orphaned" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_waitapplied{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Wait Applied" + } + ], + "title": "Resources", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 6, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_desiredready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_notready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_missing{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Missing" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_modified{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Modified" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_unknown{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Unknown" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_orphaned{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Orphaned" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_resources_count_waitapplied{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Wait Applied" + } + ], + "title": "Resources", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 26 + }, + "id": 7, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_state{exported_namespace=\"$namespace\",name=~\"$name\",state=\"Ready\"}) / sum(fleet_cluster_state{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Clusters", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 26 + }, + "id": 8, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_state{exported_namespace=\"$namespace\",name=~\"$name\",state=\"Ready\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_state{exported_namespace=\"$namespace\",name=~\"$name\",state=\"NotReady\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_state{exported_namespace=\"$namespace\",name=~\"$name\",state=\"WaitCheckIn\"})", + "legendFormat": "Wait Check In" + } + ], + "title": "Clusters", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 9, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_state{exported_namespace=\"$namespace\",name=~\"$name\",state=\"Ready\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_state{exported_namespace=\"$namespace\",name=~\"$name\",state=\"NotReady\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_state{exported_namespace=\"$namespace\",name=~\"$name\",state=\"WaitCheckIn\"})", + "legendFormat": "Wait Check In" + } + ], + "title": "Clusters", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "templating": { + "list": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "name": "namespace", + "query": "label_values(fleet_cluster_desired_ready_git_repos, exported_namespace)", + "refresh": 2, + "type": "query" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "includeAll": true, + "name": "name", + "query": "label_values(fleet_cluster_desired_ready_git_repos{exported_namespace=~\"$namespace\"}, name)", + "refresh": 2, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timezone": "utc", + "title": "Fleet / Cluster", + "uid": "fleet-cluster" +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/clustergroup.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/clustergroup.json new file mode 100644 index 0000000000..ce3df87b21 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/clustergroup.json @@ -0,0 +1,468 @@ +{ + "description": "ClusterGroup", + "graphTooltip": 1, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 0 + }, + "id": 1, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_bundle_ready{exported_namespace=\"$namespace\",name=~\"$name\"}) / sum(fleet_cluster_group_bundle_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Bundles", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 0 + }, + "id": 2, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_bundle_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_bundle_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + } + ], + "title": "Bundles", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 3, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_bundle_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_bundle_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + } + ], + "title": "Bundles", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 13 + }, + "id": 4, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "(sum(fleet_cluster_group_cluster_count{exported_namespace=\"$namespace\",name=~\"$name\"}) - sum(fleet_cluster_group_non_ready_cluster_count{exported_namespace=\"$namespace\",name=~\"$name\"})) / sum(fleet_cluster_group_cluster_count{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Clusters", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 13 + }, + "id": 5, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_cluster_count{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Total" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_non_ready_cluster_count{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Non Ready" + } + ], + "title": "Clusters", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 6, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_cluster_count{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Total" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_non_ready_cluster_count{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Non Ready" + } + ], + "title": "Clusters", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 26 + }, + "id": 7, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_ready{exported_namespace=\"$namespace\",name=~\"$name\"}) / sum(fleet_cluster_group_resource_count_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Resources", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 26 + }, + "id": 8, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_notready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_missing{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Missing" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_modified{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Modified" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_orphaned{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Orphaned" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_unknown{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Unknown" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_waitapplied{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Wait Applied" + } + ], + "title": "Resources", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 9, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_notready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_missing{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Missing" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_modified{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Modified" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_orphaned{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Orphaned" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_unknown{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Unknown" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_cluster_group_resource_count_waitapplied{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Wait Applied" + } + ], + "title": "Resources", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "templating": { + "list": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "name": "namespace", + "query": "label_values(fleet_cluster_group_bundle_desired_ready, exported_namespace)", + "refresh": 2, + "type": "query" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "includeAll": true, + "name": "name", + "query": "label_values(fleet_cluster_group_bundle_desired_ready{exported_namespace=~\"$namespace\"}, name)", + "refresh": 2, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timezone": "utc", + "title": "Fleet / ClusterGroup", + "uid": "fleet-cluster-group" +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/controller-runtime.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/controller-runtime.json new file mode 100644 index 0000000000..23a81f2a8c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/controller-runtime.json @@ -0,0 +1,454 @@ +{ + "description": "Controller Runtime", + "graphTooltip": 1, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "controller_runtime_active_workers{job=\"$job\", namespace=\"$namespace\"}", + "legendFormat": "{{controller}} {{instance}}" + } + ], + "title": "Number of Workers in Use", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 2, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(rate(controller_runtime_reconcile_errors_total{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, pod)", + "legendFormat": "{{instance}} {{pod}}" + } + ], + "title": "Reconciliation Error Count per Controller", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 3, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(rate(controller_runtime_reconcile_total{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, pod)", + "legendFormat": "{{instance}} {{pod}}" + } + ], + "title": "Total Reconciliation Count per Controller", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 4, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "workqueue_depth{job=\"$job\", namespace=\"$namespace\"}", + "legendFormat": "{{instance}} {{pod}}" + } + ], + "title": "WorkQueue Depth", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 32 + }, + "id": 5, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "histogram_quantile(0.50, sum(rate(workqueue_queue_duration_seconds_bucket{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, name, le))", + "legendFormat": "P50 {{name}}" + } + ], + "title": "Seconds for Items Stay in Queue (before being requested) P50", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 6, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "histogram_quantile(0.90, sum(rate(workqueue_queue_duration_seconds_bucket{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, name, le))", + "legendFormat": "P90 {{name}}" + } + ], + "title": "Seconds for Items Stay in Queue (before being requested) P90", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 7, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "histogram_quantile(0.99, sum(rate(workqueue_queue_duration_seconds_bucket{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, name, le))", + "legendFormat": "P99 {{name}}" + } + ], + "title": "Seconds for Items Stay in Queue (before being requested) P99", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 56 + }, + "id": 8, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(rate(workqueue_adds_total{job=\"$job\", namespace=\"$namespace\"}[2m])) by (instance, name)", + "legendFormat": "{{name}} {{instance}}" + } + ], + "title": "Work Queue Add Rate", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 64 + }, + "id": 9, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "rate(workqueue_unfinished_work_seconds{job=\"$job\", namespace=\"$namespace\"}[5m])", + "legendFormat": "{{name}} {{instance}}" + } + ], + "title": "Unfinished Seconds", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 72 + }, + "id": 10, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "histogram_quantile(0.50, sum(rate(workqueue_work_duration_seconds_bucket{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, name, le))", + "legendFormat": "P50 {{name}}" + } + ], + "title": "Seconds Processing Items from WorkQueue - 50th Percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 80 + }, + "id": 11, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "histogram_quantile(0.90, sum(rate(workqueue_work_duration_seconds_bucket{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, name, le))", + "legendFormat": "P90 {{name}}" + } + ], + "title": "Seconds Processing Items from WorkQueue - 90th Percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 88 + }, + "id": 12, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "histogram_quantile(0.99, sum(rate(workqueue_work_duration_seconds_bucket{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, name, le))", + "legendFormat": "P99 {{name}}" + } + ], + "title": "Seconds Processing Items from WorkQueue - 99th Percentile", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": null, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 96 + }, + "id": 13, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(rate(workqueue_retries_total{job=\"$job\", namespace=\"$namespace\"}[5m])) by (instance, name)", + "legendFormat": "{{name}} {{instance}}" + } + ], + "title": "Work Queue Retries Rate", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "templating": { + "list": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "name": "namespace", + "query": "label_values(controller_runtime_reconcile_total, namespace)", + "refresh": 2, + "type": "query" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "name": "job", + "query": "label_values(controller_runtime_reconcile_total{namespace=~\"$namespace\"}, job)", + "refresh": 2, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timezone": "utc", + "title": "Fleet / Controller-Runtime", + "uid": "fleet-controller-runtime" +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/gitrepo.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/gitrepo.json new file mode 100644 index 0000000000..1a50c2937d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/fleet/gitrepo.json @@ -0,0 +1,325 @@ +{ + "description": "GitRepo", + "graphTooltip": 1, + "panels": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 0 + }, + "id": 1, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_ready_clusters{exported_namespace=\"$namespace\",name=~\"$name\"}) / sum(fleet_gitrepo_desired_ready_clusters{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Clusters", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 0 + }, + "id": 2, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_desired_ready_clusters{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_ready_clusters{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + } + ], + "title": "Clusters", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 3, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_desired_ready_clusters{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_ready_clusters{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + } + ], + "title": "Clusters", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": "percentunit" + } + }, + "gridPos": { + "h": 5, + "w": 7, + "x": 0, + "y": 13 + }, + "id": 4, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_ready{exported_namespace=\"$namespace\",name=~\"$name\"}) / sum(fleet_gitrepo_resources_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})" + } + ], + "title": "Ready Resources", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 5, + "w": 17, + "x": 7, + "y": 13 + }, + "id": 5, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_not_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_missing{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Missing" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_modified{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Modified" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_unknown{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Unknown" + } + ], + "title": "Resources", + "type": "stat" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Mixed --" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "unit": null + } + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 6, + "pluginVersion": "v11.0.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_desired_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Desired Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_not_ready{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Not Ready" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_missing{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Missing" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_modified{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Modified" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(fleet_gitrepo_resources_unknown{exported_namespace=\"$namespace\",name=~\"$name\"})", + "legendFormat": "Unknown" + } + ], + "title": "Resources", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "templating": { + "list": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "name": "namespace", + "query": "label_values(fleet_gitrepo_desired_ready_clusters, exported_namespace)", + "refresh": 2, + "type": "query" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "includeAll": true, + "name": "name", + "query": "label_values(fleet_gitrepo_desired_ready_clusters{exported_namespace=~\"$namespace\"}, name)", + "refresh": 2, + "type": "query" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timezone": "utc", + "title": "Fleet / GitRepo", + "uid": "fleet-gitrepo" +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/home/rancher-default-home.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/home/rancher-default-home.json new file mode 100644 index 0000000000..3fce207561 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/home/rancher-default-home.json @@ -0,0 +1,1290 @@ +{ + "annotations": { + "list": [] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 1, + "title": "", + "type": "welcome" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 4 + }, + "height": "180px", + "id": 6, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "(1 - (avg(irate({__name__=~\"node_cpu_seconds_total|windows_cpu_time_total\",mode=\"idle\"}[5m])))) * 100", + "format": "time_series", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "65, 90", + "title": "CPU Utilization", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 4 + }, + "height": "180px", + "id": 4, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "(1 - sum({__name__=~\"node_memory_MemAvailable_bytes|windows_os_physical_memory_free_bytes\"}) / sum({__name__=~\"node_memory_MemTotal_bytes|windows_cs_physical_memory_bytes\"})) * 100", + "format": "time_series", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "65, 90", + "title": "Memory Utilization", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 4 + }, + "height": "180px", + "id": 7, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "(1 - (((sum(node_filesystem_free_bytes{device!~\"rootfs|HarddiskVolume.+\"}) OR on() vector(0)) + (sum(windows_logical_disk_free_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) OR on() vector(0))) / ((sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\"}) OR on() vector(0)) + (sum(windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) OR on() vector(0))))) * 100", + "format": "time_series", + "interval": "10s", + "intervalFactor": 1, + "metric": "", + "refId": "A", + "step": 10 + } + ], + "thresholds": "65, 90", + "title": "Disk Utilization", + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 9 + }, + "height": "1px", + "id": 11, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": " cores", + "postfixFontSize": "30%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate({__name__=~\"node_cpu_seconds_total|windows_cpu_time_total\",mode!=\"idle\"}[5m]))", + "format": "time_series", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "CPU Used", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 9 + }, + "height": "1px", + "id": 12, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": " cores", + "postfixFontSize": "30%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_node_status_allocatable_cpu_cores{}) OR sum(kube_node_status_allocatable{resource=\"cpu\",unit=\"core\"})", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "CPU Total", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 9 + }, + "height": "1px", + "id": 9, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "20%", + "prefix": "", + "prefixFontSize": "20%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum({__name__=~\"node_memory_MemTotal_bytes|windows_cs_physical_memory_bytes\"}) - sum({__name__=~\"node_memory_MemAvailable_bytes|windows_os_physical_memory_free_bytes\"})", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Memory Used", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 12, + "y": 9 + }, + "height": "1px", + "id": 10, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(kube_node_status_allocatable_memory_bytes{}) OR sum(kube_node_status_allocatable{resource=\"memory\", unit=\"byte\"})", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Memory Total", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 16, + "y": 9 + }, + "height": "1px", + "id": 13, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "(sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\"}) - sum(node_filesystem_free_bytes{device!~\"rootfs|HarddiskVolume.+\"}) OR on() vector(0)) + (sum(windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) - sum(windows_logical_disk_free_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) OR on() vector(0))", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Disk Used", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "Prometheus", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "format": "bytes", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 20, + "y": 9 + }, + "height": "1px", + "id": 14, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "(sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\"}) OR on() vector(0)) + (sum(windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) OR on() vector(0))", + "interval": "10s", + "intervalFactor": 1, + "refId": "A", + "step": 10 + } + ], + "thresholds": "", + "title": "Disk Total", + "type": "singlestat", + "valueFontSize": "50%", + "valueMaps": [ + { + "op": "=", + "text": "0", + "value": "null" + } + ], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 12 + }, + "hiddenSeries": false, + "id": 2051, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - (avg(irate({__name__=~\"node_cpu_seconds_total|windows_cpu_time_total\",mode=\"idle\"}[$__rate_interval])))", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "A" + }, + { + "expr": "1 - avg(irate({__name__=~\"node_cpu_seconds_total|windows_cpu_time_total\", mode=\"idle\"}[$__rate_interval])) by (instance)", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ instance }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percentunit", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 8, + "x": 8, + "y": 12 + }, + "hiddenSeries": false, + "id": 2052, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "100 * (1 - sum({__name__=~\"node_memory_MemAvailable_bytes|windows_os_physical_memory_free_bytes\"}) / sum({__name__=~\"node_memory_MemTotal_bytes|windows_cs_physical_memory_bytes\"}))", + "format": "time_series", + "hide": false, + "instant": false, + "intervalFactor": 1, + "legendFormat": "Cluster", + "refId": "A" + }, + { + "expr": "100 * (1- sum({__name__=~\"node_memory_MemAvailable_bytes|windows_os_physical_memory_free_bytes\"}) by (instance) / sum({__name__=~\"node_memory_MemTotal_bytes|windows_cs_physical_memory_bytes\"}) by (instance))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "{{ instance }}", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 12 + }, + "hiddenSeries": false, + "id": 2053, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(1 - ((sum(node_filesystem_free_bytes{device!~\"rootfs|HarddiskVolume.+\"}) OR on() vector(0)) + (sum(windows_logical_disk_free_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"} OR on() vector(0)))) / ((sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\"}) OR on() vector(0)) + (sum(windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) OR on() vector(0)))) * 100", + "legendFormat": "Cluster", + "refId": "A" + }, + { + "expr": "(1 - (sum(node_filesystem_free_bytes{device!~\"rootfs|HarddiskVolume.+\"}) by (instance)) / sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\"}) by (instance)) * 100", + "hide": false, + "legendFormat": "{{ instance }}", + "refId": "B" + }, + { + "expr": "(1 - (sum(windows_logical_disk_free_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) by (instance)) / sum(windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\"}) by (instance)) * 100", + "hide": false, + "legendFormat": "{{ instance }}", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "percent", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "folderId": 0, + "gridPos": { + "h": 15, + "w": 12, + "x": 0, + "y": 18 + }, + "headings": true, + "id": 3, + "limit": 30, + "links": [], + "query": "", + "recent": true, + "search": true, + "starred": false, + "tags": [], + "title": "Dashboards", + "type": "dashlist" + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 2055, + "options": { + "content": "## About Rancher Monitoring\n\nRancher Monitoring is a Helm chart developed by Rancher that is powered by [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator). It is based on the upstream [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack) Helm chart maintained by the Prometheus community.\n\nBy default, the chart deploys Grafana alongside a set of Grafana dashboards curated by the [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus) project.\n\nFor more information on how Rancher Monitoring differs from [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack), please view the CHANGELOG.md of the rancher-monitoring chart located in the [rancher/charts](https://github.com/rancher/charts) repository.\n\nFor more information about how to configure Rancher Monitoring, please view the [Rancher docs](https://rancher.com/docs/rancher/v2.x/en/).\n\n", + "mode": "markdown" + }, + "pluginVersion": "7.1.0", + "timeFrom": null, + "timeShift": null, + "title": "", + "type": "text" + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "hidden": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ], + "type": "timepicker" + }, + "timezone": "browser", + "title": "Home", + "uid": "rancher-home-1", + "version": 5 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-etcd-nodes.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-etcd-nodes.json new file mode 100644 index 0000000000..8af4b81ce0 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-etcd-nodes.json @@ -0,0 +1,687 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 32, + "links": [], + "panels": [ + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(etcd_network_client_grpc_received_bytes_total{job=\"kube-etcd\"}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Client Traffic In ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(rate(etcd_network_client_grpc_sent_bytes_total{job=\"kube-etcd\"}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Client Traffic Out ({{instance}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "GRPC Client Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Load[5m]({{instance}})" + }, + "properties": [] + } + ] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(etcd_mvcc_db_total_size_in_bytes) by (instance)", + "interval": "", + "legendFormat": "DB Size ({{instance}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "DB Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(grpc_server_started_total{grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"}) by (instance) - sum(grpc_server_handled_total{grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"}) by (instance)", + "interval": "", + "legendFormat": "Watch Streams ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(grpc_server_started_total{grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"}) by (instance) - sum(grpc_server_handled_total{grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"}) by (instance)", + "interval": "", + "legendFormat": "Lease Watch Stream ({{instance}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Active Streams", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(etcd_server_proposals_committed_total[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Proposal Committed ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(rate(etcd_server_proposals_applied_total[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Proposal Applied ({{instance}})", + "refId": "B" + }, + { + "expr": "sum(rate(etcd_server_proposals_failed_total[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "Proposal Failed ({{instance}})", + "refId": "C" + }, + { + "expr": "sum(etcd_server_proposals_pending) by (instance)", + "interval": "", + "legendFormat": "Proposal Pending ({{instance}})", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Raft Proposals", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_started_total{grpc_type=\"unary\"}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "RPC Rate ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(rate(grpc_server_handled_total{grpc_type=\"unary\",grpc_code!=\"OK\"}[$__rate_interval])) by (instance)", + "interval": "", + "legendFormat": "RPC Failure Rate ({{instance}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RPC Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 7 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(etcd_disk_wal_fsync_duration_seconds_bucket[$__rate_interval])) by (instance, le))", + "interval": "", + "legendFormat": "WAL fsync ({{instance}})", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(etcd_disk_backend_commit_duration_seconds_bucket[$__rate_interval])) by (instance, le))", + "interval": "", + "legendFormat": "DB fsync ({{instance}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk Sync Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / etcd (Nodes)", + "uid": "rancher-etcd-nodes-1", + "version": 5 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-etcd.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-etcd.json new file mode 100644 index 0000000000..0c058cafb9 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-etcd.json @@ -0,0 +1,669 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 33, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(etcd_network_client_grpc_received_bytes_total{job=\"kube-etcd\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Client Traffic In", + "refId": "A" + }, + { + "expr": "sum(rate(etcd_network_client_grpc_sent_bytes_total{job=\"kube-etcd\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Client Traffic Out", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "GRPC Client Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [ + { + "properties": [] + } + ] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(etcd_mvcc_db_total_size_in_bytes)", + "interval": "", + "legendFormat": "DB Size", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "DB Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(grpc_server_started_total{grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total{grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"})", + "interval": "", + "legendFormat": "Watch Streams", + "refId": "A" + }, + { + "expr": "sum(grpc_server_started_total{grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total{grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"})", + "interval": "", + "legendFormat": "Lease Watch Stream", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Active Streams", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(etcd_server_proposals_committed_total[$__rate_interval]))", + "interval": "", + "legendFormat": "Proposal Committed", + "refId": "A" + }, + { + "expr": "sum(rate(etcd_server_proposals_applied_total[$__rate_interval]))", + "interval": "", + "legendFormat": "Proposal Applied", + "refId": "B" + }, + { + "expr": "sum(rate(etcd_server_proposals_failed_total[$__rate_interval]))", + "interval": "", + "legendFormat": "Proposal Failed", + "refId": "C" + }, + { + "expr": "sum(etcd_server_proposals_pending)", + "interval": "", + "legendFormat": "Proposal Pending", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Raft Proposals", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_started_total{grpc_type=\"unary\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "RPC Rate", + "refId": "A" + }, + { + "expr": "sum(rate(grpc_server_handled_total{grpc_type=\"unary\",grpc_code!=\"OK\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "RPC Failure Rate", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "RPC Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 7 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(etcd_disk_wal_fsync_duration_seconds_bucket[$__rate_interval])) by (instance, le))", + "interval": "", + "legendFormat": "WAL fsync", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(etcd_disk_backend_commit_duration_seconds_bucket[$__rate_interval])) by (instance, le))", + "interval": "", + "legendFormat": "DB fsync", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk Sync Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / etcd", + "uid": "rancher-etcd-1", + "version": 4 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-k8s-components-nodes.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-k8s-components-nodes.json new file mode 100644 index 0000000000..b31358eaaf --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-k8s-components-nodes.json @@ -0,0 +1,527 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 30, + "links": [], + "panels": [ + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(apiserver_request_total[$__rate_interval])) by (instance, code)", + "interval": "", + "legendFormat": "{{code}}({{instance}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "API Server Request Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Load[5m]({{instance}})" + }, + "properties": [] + } + ] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"deployment\"}) by (instance, name)", + "interval": "", + "legendFormat": "Deployment Depth ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"volumes\"}) by (instance, name)", + "interval": "", + "legendFormat": "Volumes Depth ({{instance}})", + "refId": "B" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"replicaset\"}) by (instance, name)", + "interval": "", + "legendFormat": "ReplicaSet Depth ({{instance}})", + "refId": "C" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"service\"}) by (instance, name)", + "interval": "", + "legendFormat": "Service Depth ({{instance}})", + "refId": "D" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"serviceaccount\"}) by (instance, name)", + "interval": "", + "legendFormat": "ServiceAccount Depth ({{instance}})", + "refId": "E" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"endpoint\"}) by (instance, name)", + "interval": "", + "legendFormat": "Endpoint Depth ({{instance}})", + "refId": "F" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"daemonset\"}) by (instance, name)", + "interval": "", + "legendFormat": "DaemonSet Depth ({{instance}})", + "refId": "G" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"statefulset\"}) by (instance, name)", + "interval": "", + "legendFormat": "StatefulSet Depth ({{instance}})", + "refId": "H" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"replicationmanager\"}) by (instance, name)", + "interval": "", + "legendFormat": "ReplicationManager Depth ({{instance}})", + "refId": "I" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Controller Manager Queue Depth", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(kube_pod_status_scheduled{condition=\"false\"})", + "interval": "", + "legendFormat": "Failed To Schedule", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pod Scheduling Status", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{instance}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(nginx_ingress_controller_nginx_process_connections{state=\"reading\"}) by (instance)", + "interval": "", + "legendFormat": "Reading ({{instance}})", + "refId": "A" + }, + { + "expr": "sum(nginx_ingress_controller_nginx_process_connections{state=\"waiting\"}) by (instance)", + "interval": "", + "legendFormat": "Waiting ({{instance}})", + "refId": "B" + }, + { + "expr": "sum(nginx_ingress_controller_nginx_process_connections{state=\"writing\"}) by (instance)", + "interval": "", + "legendFormat": "Writing ({{instance}})", + "refId": "C" + }, + { + "expr": "sum(ceil(increase(nginx_ingress_controller_nginx_process_connections_total{state=\"accepted\"}[$__rate_interval]))) by (instance)", + "interval": "", + "legendFormat": "Accepted ({{instance}})", + "refId": "D" + }, + { + "expr": "sum(ceil(increase(nginx_ingress_controller_nginx_process_connections_total{state=\"handled\"}[$__rate_interval]))) by (instance)", + "interval": "", + "legendFormat": "Handled ({{instance}})", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Ingress Controller Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Kubernetes Components (Nodes)", + "uid": "rancher-k8s-components-nodes-1", + "version": 5 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-k8s-components.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-k8s-components.json new file mode 100644 index 0000000000..44cf97f9fd --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/k8s/rancher-k8s-components.json @@ -0,0 +1,519 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 31, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(apiserver_request_total[$__rate_interval])) by (code)", + "interval": "", + "legendFormat": "{{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "API Server Request Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Load[5m]({{instance}})" + }, + "properties": [] + } + ] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"deployment\"}) by (name)", + "interval": "", + "legendFormat": "Deployment Depth", + "refId": "A" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"volumes\"}) by (name)", + "interval": "", + "legendFormat": "Volumes Depth", + "refId": "B" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"replicaset\"}) by (name)", + "interval": "", + "legendFormat": "Replicaset Depth", + "refId": "C" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"service\"}) by (name)", + "interval": "", + "legendFormat": "Service Depth", + "refId": "D" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"serviceaccount\"}) by (name)", + "interval": "", + "legendFormat": "ServiceAccount Depth", + "refId": "E" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"endpoint\"}) by (name)", + "interval": "", + "legendFormat": "Endpoint Depth", + "refId": "F" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"daemonset\"}) by (name)", + "interval": "", + "legendFormat": "DaemonSet Depth", + "refId": "G" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"statefulset\"}) by (name)", + "interval": "", + "legendFormat": "StatefulSet Depth", + "refId": "H" + }, + { + "expr": "sum(workqueue_depth{component=\"kube-controller-manager\", name=\"replicationmanager\"}) by (name)", + "interval": "", + "legendFormat": "ReplicationManager Depth", + "refId": "I" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Controller Manager Queue Depth", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(kube_pod_status_scheduled{condition=\"false\"})", + "interval": "", + "legendFormat": "Failed To Schedule", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Pod Scheduling Status", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(nginx_ingress_controller_nginx_process_connections{state=\"reading\"})", + "interval": "", + "legendFormat": "Reading", + "refId": "A" + }, + { + "expr": "sum(nginx_ingress_controller_nginx_process_connections{state=\"waiting\"})", + "interval": "", + "legendFormat": "Waiting", + "refId": "B" + }, + { + "expr": "sum(nginx_ingress_controller_nginx_process_connections{state=\"writing\"})", + "interval": "", + "legendFormat": "Writing", + "refId": "C" + }, + { + "expr": "sum(ceil(increase(nginx_ingress_controller_nginx_process_connections_total{state=\"accepted\"}[$__rate_interval])))", + "interval": "", + "legendFormat": "Accepted", + "refId": "D" + }, + { + "expr": "sum(ceil(increase(nginx_ingress_controller_nginx_process_connections_total{state=\"handled\"}[$__rate_interval])))", + "interval": "", + "legendFormat": "Handled", + "refId": "E" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Ingress Controller Connections", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Kubernetes Components", + "uid": "rancher-k8s-components-1", + "version": 5 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/logging/fluentbit.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/logging/fluentbit.json new file mode 100644 index 0000000000..b00582c8a8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/logging/fluentbit.json @@ -0,0 +1,760 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:7", + "builtIn": 1, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Monitoring of the logging-stack", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 13042, + "graphTooltip": 1, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 19, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 1 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:1802", + "alias": "/Error.*/", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "\nsum(rate(fluentbit_output_retries_total[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Retry rate", + "range": true, + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(fluentbit_output_errors_total[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error rate", + "range": true, + "refId": "C" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Fluentbit output error/retry rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1697", + "format": "ops", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:1698", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "Input and output total rates", + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 1 + }, + "hiddenSeries": false, + "id": 44, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(fluentbit_input_records_total[1m]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "input", + "range": true, + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(fluentbit_output_proc_records_total[1m]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "output", + "range": true, + "refId": "B" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Fluentbit input/output rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 30, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(fluentbit_output_retries_total[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current retry count", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 7 + }, + "hiddenSeries": false, + "id": 45, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(fluentbit_output_errors_total[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current error count", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 13 + }, + "hiddenSeries": false, + "id": 46, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(fluentbit_input_records_total[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Input records total", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 13 + }, + "hiddenSeries": false, + "id": 47, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "sum(rate(fluentbit_filter_drop_records_total[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "range": true, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Dropped records total", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "refresh": false, + "schemaVersion": 39, + "tags": [ + "logging", + "fluentbit" + ], + "templating": { + "list": [ + { + "hide": 2, + "name": "DS_PROMETHEUS", + "query": "prometheus", + "skipUrlSync": false, + "type": "constant" + } + ] + }, + "time": { + "from": "2024-08-20T15:06:03.311Z", + "to": "2024-08-20T21:06:03.311Z" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "utc", + "title": "Rancher / Fluentbit", + "uid": "rancher-logging-fluentbit", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/logging/fluentd.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/logging/fluentd.json new file mode 100644 index 0000000000..8861425ce1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/logging/fluentd.json @@ -0,0 +1,3221 @@ +{ + "annotations": { + "list": [ + { + "$$hashKey": "object:7", + "builtIn": 1, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Monitoring of the logging-stack", + "editable": true, + "fiscalYearStartMonth": 0, + "gnetId": 13042, + "graphTooltip": 1, + "links": [], + "liveNow": false, + "panels": [ + { + "collapsed": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 19, + "panels": [], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "General", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "If you see errors then you probbaly have serious issues with log processing, see https://docs.fluentd.org/buffer#handling-unrecoverable-errors\n\nRetries are normal but should occur only from time to time, otherwise check for network errors or destination is too slow and requires additional tuning per given provider.", + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 1 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:1802", + "alias": "/Error.*/", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_retry_count[1m]))", + "format": "time_series", + "hide": false, + "intervalFactor": 1, + "legendFormat": "Retry rate", + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_num_errors[1m]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Error rate", + "refId": "C" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Fluentd output error/retry rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1697", + "format": "ops", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:1698", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "Input and output total rates", + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 1 + }, + "hiddenSeries": false, + "id": 44, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_input_status_num_records_total[1m]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "input", + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_write_count[1m]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "output", + "refId": "B" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Fluentd input/output rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "This should not reach 0 otherwise logs are blocked from processing or even dropped", + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 1 + }, + "hiddenSeries": false, + "id": 20, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "min(fluentd_output_status_buffer_available_space_ratio)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "lowest across all hosts", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Fluentd output status buffer available space ratio", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:918", + "decimals": 0, + "format": "percent", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:919", + "decimals": 0, + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "total flush time", + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 6 + }, + "hiddenSeries": false, + "id": 21, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:906", + "alias": "count", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_flush_time_count[1m]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "time", + "refId": "A" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_slow_flush_count[1m]))", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "count", + "refId": "B" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Fluentd output status flush time count rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:400", + "decimals": 0, + "format": "ms", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:401", + "decimals": 0, + "format": "short", + "logBase": 1, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "Current total size of stage and queue buffers.\nfluentd_output_status_buffer_total_bytes", + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 6 + }, + "hiddenSeries": false, + "id": 13, + "legend": { + "alignAsTable": false, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_buffer_total_bytes) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current total size of stage and queue buffers", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:321", + "format": "bytes", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:322", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 8, + "x": 16, + "y": 6 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "10.3.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_buffer_queue_length)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "total", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Fluentd output buffer queue", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1460", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:1461", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "collapsed": true, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 17, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_input_status_num_records_total", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 12 + }, + "hiddenSeries": false, + "id": 39, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_input_status_num_records_total[1m])) ", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "total", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Input entries rate (total)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_input_status_num_records_total", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 12 + }, + "hiddenSeries": false, + "id": 47, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_input_status_num_records_total[1m])) by (hostname)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{hostname}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Input entries rate per hostname", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_input_status_num_records_total", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 18 + }, + "hiddenSeries": false, + "id": 60, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_input_status_num_records_total[1m])) by (namespace)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Input entries rate per namespace", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_input_status_num_records_total", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 18 + }, + "hiddenSeries": false, + "id": 48, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_input_status_num_records_total[1m])) by (instance)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Input entries rate per instance", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Input details", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 59, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_input_status_num_records_total", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 25 + }, + "hiddenSeries": false, + "id": 49, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_input_status_num_records_total[1m])) by (tag)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{tag}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Input entries rate per tag", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Input details (warning, very slow!)", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 41, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_buffer_stage_length", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 32 + }, + "hiddenSeries": false, + "id": 22, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_buffer_stage_length) by (pod, type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current length of stage buffers", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_buffer_stage_byte_size", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 32 + }, + "hiddenSeries": false, + "id": 23, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_buffer_stage_byte_size) by (pod, type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current total size of stage buffers", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "bytes", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Buffer stage", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 43, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 39 + }, + "hiddenSeries": false, + "id": 50, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "max_over_time(fluentd_output_status_buffer_queue_length[1m])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Maximum buffer length in last 1min", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 39 + }, + "hiddenSeries": false, + "id": 25, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "max_over_time(fluentd_output_status_buffer_total_bytes[1m])", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Maximum buffer bytes in last 1min", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "bytes", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_buffer_queue_length", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 45 + }, + "hiddenSeries": false, + "id": 24, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_buffer_queue_length) by (pod, type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current length of queue buffers", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_queue_byte_size", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 45 + }, + "hiddenSeries": false, + "id": 51, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_queue_byte_size) by (pod, type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current total size of queue buffers", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "bytes", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Buffer queue", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 46, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_buffer_available_space_ratio", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 52 + }, + "hiddenSeries": false, + "id": 26, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_buffer_available_space_ratio) by (pod, type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Ratio of available space in buffer", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "percent", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Buffer space", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 53, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_retry_count", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 59 + }, + "hiddenSeries": false, + "id": 30, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_retry_count[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current retry counts", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_emit_records", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 59 + }, + "hiddenSeries": false, + "id": 33, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_emit_records[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current emit records", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_emit_count", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 65 + }, + "hiddenSeries": false, + "id": 32, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_emit_count[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current emit counts rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_rollback_count", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 65 + }, + "hiddenSeries": false, + "id": 35, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_rollback_count[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current rollback counts", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_write_count", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 71 + }, + "hiddenSeries": false, + "id": 34, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_write_count[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current write counts", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_slow_flush_count", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 71 + }, + "hiddenSeries": false, + "id": 37, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_slow_flush_count[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current slow flush counts", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_retry_wait", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 77 + }, + "hiddenSeries": false, + "id": 38, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_retry_wait[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current retry wait", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_flush_time_count", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 77 + }, + "hiddenSeries": false, + "id": 36, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_flush_time_count[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Total flush time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "ms", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Buffer retries", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 57, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_num_errors", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 84 + }, + "hiddenSeries": false, + "id": 31, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(rate(fluentd_output_status_num_errors[1m])) by (type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Current number of errors rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Buffer errors", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 55, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 91 + }, + "hiddenSeries": false, + "id": 29, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "fluentd_output_status_buffer_newest_timekey - fluentd_output_status_buffer_oldest_timekey", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Timekey diff", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_buffer_newest_timekey", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 91 + }, + "hiddenSeries": false, + "id": 27, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_buffer_newest_timekey) by (pod, type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Newest timekey in buffer", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "description": "fluentd_output_status_buffer_oldest_timekey", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 97 + }, + "hiddenSeries": false, + "id": 28, + "legend": { + "alignAsTable": false, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": false, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "expr": "sum(fluentd_output_status_buffer_oldest_timekey) by (pod, type)", + "format": "time_series", + "hide": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{pod}} {{ type }}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Oldest timekey in buffer", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:250", + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "$$hashKey": "object:251", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Buffer timekeys", + "type": "row" + } + ], + "refresh": "10s", + "schemaVersion": 39, + "tags": [ + "fluentd", + "logging" + ], + "templating": { + "list": [ + { + "hide": 2, + "name": "DS_PROMETHEUS", + "query": "prometheus", + "skipUrlSync": false, + "type": "constant" + } + ] + }, + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "utc", + "title": "Rancher / Fluentd", + "uid": "rancher-logging-fluentd", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/nodes/rancher-node-detail.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/nodes/rancher-node-detail.json new file mode 100644 index 0000000000..920fb94cf7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/nodes/rancher-node-detail.json @@ -0,0 +1,805 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 28, + "links": [], + "panels": [ + { + "aliasColors": { + "{{mode}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate({__name__=~\"node_cpu_seconds_total|windows_cpu_time_total\", instance=\"$instance\"}[$__rate_interval])) by (mode)", + "interval": "", + "legendFormat": "{{mode}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Load[5m]" + }, + "properties": [] + } + ] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_load5{instance=~\"$instance\"} OR avg_over_time(windows_system_processor_queue_length{instance=~\"$instance\"}[5m]))", + "interval": "", + "legendFormat": "Load[5m]", + "refId": "A" + }, + { + "expr": "sum(node_load1{instance=~\"$instance\"} OR avg_over_time(windows_system_processor_queue_length{instance=~\"$instance\"}[1m]))", + "interval": "", + "legendFormat": "Load[1m]", + "refId": "B" + }, + { + "expr": "sum(node_load15{instance=~\"$instance\"} OR avg_over_time(windows_system_processor_queue_length{instance=~\"$instance\"}[15m]))", + "interval": "", + "legendFormat": "Load[15m]", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Load Average", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - (node_memory_MemAvailable_bytes{instance=~\"$instance\"} OR windows_os_physical_memory_free_bytes{instance=~\"$instance\"}) / (node_memory_MemTotal_bytes{instance=~\"$instance\"} OR windows_cs_physical_memory_bytes{instance=~\"$instance\"})", + "interval": "", + "legendFormat": "Total", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{device}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - (sum(node_filesystem_free_bytes{device!~\"rootfs|HarddiskVolume.+\", instance=~\"$instance\"} OR windows_logical_disk_free_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\", instance=~\"$instance\"}) by (device) / sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\", instance=~\"$instance\"} OR windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\", instance=~\"$instance\"}) by (device))", + "interval": "", + "legendFormat": "{{device}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{device}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_disk_read_bytes_total{instance=~\"$instance\"}[$__rate_interval]) OR rate(windows_logical_disk_read_bytes_total{instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Read ({{device}})", + "refId": "A" + }, + { + "expr": "sum(rate(node_disk_written_bytes_total{instance=~\"$instance\"}[$__rate_interval]) OR rate(windows_logical_disk_write_bytes_total{instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Write ({{device}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{device}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 7 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_network_receive_errs_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) by (device) OR sum(rate(windows_net_packets_received_errors_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Receive Errors ({{device}})", + "refId": "A" + }, + { + "expr": "sum(rate(node_network_receive_packets_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) by (device) OR sum(rate(windows_net_packets_received_total_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Receive Total ({{device}})", + "refId": "B" + }, + { + "expr": "sum(rate(node_network_transmit_errs_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) by (device) OR sum(rate(windows_net_packets_outbound_errors_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Transmit Errors ({{device}})", + "refId": "C" + }, + { + "expr": "sum(rate(node_network_receive_drop_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) by (device) OR sum(rate(windows_net_packets_received_discarded_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Receive Dropped ({{device}})", + "refId": "D" + }, + { + "expr": "sum(rate(node_network_transmit_drop_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) by (device) OR sum(rate(windows_net_packets_outbound_discarded{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Transmit Dropped ({{device}})", + "refId": "E" + }, + { + "expr": "sum(rate(node_network_transmit_packets_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) by (device) OR sum(rate(windows_net_packets_sent_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Transmit Total ({{device}})", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{device}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_network_transmit_bytes_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval]) OR rate(windows_net_packets_sent_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Transmit Total ({{device}})", + "refId": "A" + }, + { + "expr": "sum(rate(node_network_receive_bytes_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval]) OR rate(windows_net_packets_received_total_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) by (device)", + "interval": "", + "legendFormat": "Receive Total ({{device}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "instance", + "query": "label_values({__name__=~\"node_exporter_build_info|windows_exporter_build_info\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Node (Detail)", + "uid": "rancher-node-detail-1", + "version": 3 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/nodes/rancher-node.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/nodes/rancher-node.json new file mode 100644 index 0000000000..367df3cc9d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/nodes/rancher-node.json @@ -0,0 +1,792 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 28, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - avg(irate({__name__=~\"node_cpu_seconds_total|windows_cpu_time_total\", instance=\"$instance\", mode=\"idle\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Total", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Load[5m]" + }, + "properties": [] + } + ] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_load5{instance=~\"$instance\"} OR avg_over_time(windows_system_processor_queue_length{instance=~\"$instance\"}[5m]))", + "interval": "", + "legendFormat": "Load[5m]", + "refId": "A" + }, + { + "expr": "sum(node_load1{instance=~\"$instance\"} OR avg_over_time(windows_system_processor_queue_length{instance=~\"$instance\"}[1m]))", + "interval": "", + "legendFormat": "Load[1m]", + "refId": "B" + }, + { + "expr": "sum(node_load15{instance=~\"$instance\"} OR avg_over_time(windows_system_processor_queue_length{instance=~\"$instance\"}[15m]))", + "interval": "", + "legendFormat": "Load[15m]", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Load Average", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - sum(node_memory_MemAvailable_bytes{instance=~\"$instance\"} OR windows_os_physical_memory_free_bytes{instance=~\"$instance\"}) / sum(node_memory_MemTotal_bytes{instance=~\"$instance\"} OR windows_cs_physical_memory_bytes{instance=~\"$instance\"})", + "interval": "", + "legendFormat": "Total", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - (sum(node_filesystem_free_bytes{device!~\"rootfs|HarddiskVolume.+\", instance=~\"$instance\"} OR windows_logical_disk_free_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\", instance=~\"$instance\"}) / sum(node_filesystem_size_bytes{device!~\"rootfs|HarddiskVolume.+\", instance=~\"$instance\"} OR windows_logical_disk_size_bytes{volume!~\"(HarddiskVolume.+|[A-Z]:.+)\", instance=~\"$instance\"}))", + "interval": "", + "legendFormat": "Total", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_disk_read_bytes_total{instance=~\"$instance\"}[$__rate_interval]) OR rate(windows_logical_disk_read_bytes_total{instance=~\"$instance\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Read", + "refId": "A" + }, + { + "expr": "sum(rate(node_disk_written_bytes_total{instance=~\"$instance\"}[$__rate_interval]) OR rate(windows_logical_disk_write_bytes_total{instance=~\"$instance\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Write", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 7 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(rate(node_network_receive_errs_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_received_errors_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Receive Errors", + "refId": "A" + }, + { + "expr": "(sum(rate(node_network_receive_packets_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_received_total_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Receive Total", + "refId": "B" + }, + { + "expr": "(sum(rate(node_network_transmit_errs_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_outbound_errors_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Transmit Errors", + "refId": "C" + }, + { + "expr": "(sum(rate(node_network_receive_drop_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_received_discarded_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Receive Dropped", + "refId": "D" + }, + { + "expr": "(sum(rate(node_network_transmit_drop_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_outbound_discarded{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Transmit Dropped", + "refId": "E" + }, + { + "expr": "(sum(rate(node_network_transmit_packets_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0)) + (sum(rate(windows_net_packets_sent_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval])) OR on() vector(0))", + "interval": "", + "legendFormat": "Transmit Total", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(node_network_transmit_bytes_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval]) OR rate(windows_net_packets_sent_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Transmit Total", + "refId": "A" + }, + { + "expr": "sum(rate(node_network_receive_bytes_total{device!~\"lo|veth.*|docker.*|flannel.*|cali.*|cbr.*\", instance=~\"$instance\"}[$__rate_interval]) OR rate(windows_net_packets_received_total_total{nic!~'.*isatap.*|.*VPN.*|.*Pseudo.*|.*tunneling.*', instance=~\"$instance\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Receive Total", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "instance", + "query": "label_values({__name__=~\"node_exporter_build_info|windows_exporter_build_info\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Node", + "uid": "rancher-node-1", + "version": 3 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/performance/performance-debugging.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/performance/performance-debugging.json new file mode 100644 index 0000000000..454bc39390 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/performance/performance-debugging.json @@ -0,0 +1,1652 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (handler_name) (rate(lasso_controller_reconcile_time_seconds_sum[5m]))\n/\nsum by (handler_name) (rate(lasso_controller_reconcile_time_seconds_count[5m])))", + "interval": "", + "legendFormat": "{{handler_name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Handler Average Execution Times Over Last 5 Minutes (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1390", + "format": "short", + "label": "Execution Time in Seconds", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:1391", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 8 + }, + "hiddenSeries": false, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (resource, method, code) (rate(steve_api_request_time_sum{resource!=\"subscribe\"}[5m]))\n/\nsum by (resource, method, code) (rate(steve_api_request_time_count{resource!=\"subscribe\"}[5m])))", + "interval": "", + "legendFormat": "{{resource}} {{method}} {{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Rancher API Average Request Times Over Last 5 Minutes (Top 20) (Subscribes Omitted)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:178", + "format": "ms", + "label": "", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:179", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 16 + }, + "hiddenSeries": false, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "rate(steve_api_request_time_sum{resource=\"subscribe\"}[5m])\n/\nrate(steve_api_request_time_count{resource=\"subscribe\"}[5m])", + "interval": "", + "legendFormat": "{{resource}} {{method}} {{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Subscribe Average Request Times Over Last 5 Minutes", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:368", + "format": "ms", + "label": "", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:369", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 24 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,workqueue_depth)", + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Lasso Controller Work Queue Depth (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1553", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:1554", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 16, + "x": 0, + "y": 32 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (id, resource, method, code) (steve_api_total_requests))", + "instant": false, + "interval": "", + "legendFormat": "{{id}} {{resource}} {{method}} {{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Number of Rancher Requests (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:290", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:291", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 16, + "x": 0, + "y": 45 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (id, resource, method) (steve_api_total_requests{code!=\"200\",code!=\"201\"}))", + "interval": "", + "legendFormat": "{{id}} {{resource}} {{method}} {{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Number of Failed Rancher API Requests (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:428", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:429", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 54 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (resource, method, code) (rate(k8s_proxy_store_request_time_sum[5m]))\n/\nsum by (resource, method, code) (rate(k8s_proxy_store_request_time_count[5m])))", + "interval": "", + "legendFormat": "{{resource}} {{method}} {{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "K8s Proxy Store Average Request Times Over Last 5 Minutes (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:662", + "format": "ms", + "label": "", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:663", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 62 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (resource, method, code) (rate(k8s_proxy_client_request_time_sum[5m]))\n/\nsum by (resource, method, code) (rate(k8s_proxy_client_request_time_count[5m])))", + "interval": "", + "legendFormat": "{{resource}} {{method}} {{code}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "K8s Proxy Client Average Request Times Over Last 5 Minutes (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1710", + "format": "ms", + "label": "", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:1711", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 70 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,lasso_controller_total_cached_object)", + "interval": "", + "legendFormat": "{{kind}} {{version}} {{group}} {{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Cached Objects by GroupVersionKind (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:744", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:745", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 78 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (handler_name) (\nlasso_controller_total_handler_execution\n))", + "interval": "", + "legendFormat": "{{handler_name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Lasso Handler Executions (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:824", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:825", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 86 + }, + "hiddenSeries": false, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20, sum by (handler_name,controller_name) (\nincrease(lasso_controller_total_handler_execution[2m])\n))", + "interval": "", + "legendFormat": "{{controller_name}}.{{handler_name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Handler Executions Over Last 2 Minutes (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 94 + }, + "hiddenSeries": false, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (handler_name) (\nlasso_controller_total_handler_execution{has_error=\"true\"}\n))", + "interval": "", + "legendFormat": "{{handler_name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Total Handler Executions with Error (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1230", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:1231", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 102 + }, + "hiddenSeries": false, + "id": 34, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,sum by (handler_name,controller_name) (\nincrease(lasso_controller_total_handler_execution{has_error=\"true\"}[2m])\n))", + "interval": "", + "legendFormat": "{{controller_name}}.{{handler_name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Handler Executions Over Last 2 Minutes (Top 20)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 110 + }, + "hiddenSeries": false, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "topk(20,session_server_total_transmit_bytes)", + "interval": "", + "legendFormat": "{{clientkey}} {{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Data Transmitted by Remote Dialer Sessions (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1953", + "format": "decbytes", + "label": "", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:1954", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "description": "", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 118 + }, + "hiddenSeries": false, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "exemplar": true, + "expr": "session_server_total_transmit_error_bytes", + "interval": "", + "legendFormat": "{{clientkey}} {{pod}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Errors for Remote Dialer Sessions (Top 20)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:2045", + "format": "ms", + "label": "Error Data", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:2046", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 126 + }, + "hiddenSeries": false, + "id": 26, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "exemplar": true, + "expr": "session_server_total_add_websocket_session - (session_server_total_remove_websocket_session or (0 * session_server_total_add_websocket_session))", + "interval": "", + "legendFormat": "{{clientkey}} {{pod}}", + "range": true, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Remote Dialer Active Connections (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:2199", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:2200", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 134 + }, + "hiddenSeries": false, + "id": 35, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "exemplar": true, + "expr": "rate(session_server_total_remove_connections[$__rate_interval])", + "interval": "", + "legendFormat": "{{clientkey}} {{pod}}", + "range": true, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Remote Dialer Removed Connections Rate (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:2199", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:2200", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 142 + }, + "hiddenSeries": false, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "9.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "editorMode": "code", + "exemplar": true, + "expr": "rate(session_server_total_add_connections[$__rate_interval])", + "interval": "", + "legendFormat": "{{clientkey}} {{pod}}", + "range": true, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Remote Dialer Added Connections Rate (Top 20)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:2117", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:2118", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "schemaVersion": 37, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": false, + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Rancher Performance Debugging", + "uid": "tfrfU0a7k", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/pods/rancher-pod-containers.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/pods/rancher-pod-containers.json new file mode 100644 index 0000000000..cf78a2204c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/pods/rancher-pod-containers.json @@ -0,0 +1,636 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 28, + "iteration": 1618265214337, + "links": [], + "panels": [ + { + "aliasColors": { + "{{container}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_cfs_throttled_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\", container!=\"\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "CFS throttled ({{container}})", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_system_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) by (container) OR sum(rate(windows_container_cpu_usage_seconds_kernelmode{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "System ({{container}})", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) by (container) OR sum(rate(windows_container_cpu_usage_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Total ({{container}})", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_user_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) by (container) OR sum(rate(windows_container_cpu_usage_seconds_usermode{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "User ({{container}})", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "cpu", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{container}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_working_set_bytes{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\", container!=\"\"} OR windows_container_memory_usage_commit_bytes{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\", container!=\"\"}) by (container)", + "interval": "", + "legendFormat": "({{container}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{container}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container) OR sum(irate(windows_container_network_receive_packets_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Receive Total ({{container}})", + "refId": "A" + }, + { + "expr": "sum(irate(container_network_transmit_packets_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container) OR sum(irate(windows_container_network_transmit_packets_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Transmit Total ({{container}})", + "refId": "B" + }, + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container) OR sum(irate(windows_container_network_receive_packets_dropped_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Receive Dropped ({{container}})", + "refId": "C" + }, + { + "expr": "sum(irate(container_network_receive_errors_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Receive Errors ({{container}})", + "refId": "D" + }, + { + "expr": "sum(irate(container_network_transmit_errors_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Transmit Errors ({{container}})", + "refId": "E" + }, + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container) OR sum(irate(windows_container_network_transmit_packets_dropped_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Transmit Dropped ({{container}})", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{container}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container) OR sum(irate(windows_container_network_receive_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Receive Total ({{container}})", + "refId": "A" + }, + { + "expr": "sum(irate(container_network_transmit_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container) OR sum(irate(windows_container_network_transmit_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Transmit Total ({{container}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{container}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_fs_writes_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Write ({{container}})", + "refId": "A" + }, + { + "expr": "sum(rate(container_fs_reads_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) by (container)", + "interval": "", + "legendFormat": "Read ({{container}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "query": "label_values(kube_pod_info{}, namespace)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "pod", + "query": "label_values(kube_pod_info{namespace=\"$namespace\"}, pod)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Pod (Containers)", + "uid": "rancher-pod-containers-1", + "version": 8 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/pods/rancher-pod.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/pods/rancher-pod.json new file mode 100644 index 0000000000..4859eccc74 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/pods/rancher-pod.json @@ -0,0 +1,636 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 28, + "iteration": 1618265214337, + "links": [], + "panels": [ + { + "aliasColors": { + "": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_cfs_throttled_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\", container!=\"\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "CFS throttled", + "refId": "A" + }, + { + "expr": "sum(rate(container_cpu_system_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) OR sum(rate(windows_container_cpu_usage_seconds_kernelmode{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "System", + "refId": "B" + }, + { + "expr": "sum(rate(container_cpu_usage_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) OR sum(rate(windows_container_cpu_usage_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Total", + "refId": "C" + }, + { + "expr": "sum(rate(container_cpu_user_seconds_total{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval])) OR sum(rate(windows_container_cpu_usage_seconds_usermode{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "User", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "cpu", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_working_set_bytes{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\", container!=\"\"} OR windows_container_memory_usage_commit_bytes{container!=\"POD\",namespace=~\"$namespace\",pod=~\"$pod\", container!=\"\"})", + "interval": "", + "legendFormat": "Total", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) OR sum(irate(windows_container_network_receive_packets_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Receive Total", + "refId": "A" + }, + { + "expr": "sum(irate(container_network_transmit_packets_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) OR sum(irate(windows_container_network_transmit_packets_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Transmit Total", + "refId": "B" + }, + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) OR sum(irate(windows_container_network_receive_packets_dropped_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Receive Dropped", + "refId": "C" + }, + { + "expr": "sum(irate(container_network_receive_errors_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Receive Errors", + "refId": "D" + }, + { + "expr": "sum(irate(container_network_transmit_errors_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Transmit Errors", + "refId": "E" + }, + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) OR sum(irate(windows_container_network_transmit_packets_dropped_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Transmit Dropped", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) OR sum(irate(windows_container_network_receive_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Receive Total", + "refId": "A" + }, + { + "expr": "sum(irate(container_network_transmit_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval])) OR sum(irate(windows_container_network_transmit_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Transmit Total", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_fs_writes_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Write", + "refId": "A" + }, + { + "expr": "sum(rate(container_fs_reads_bytes_total{namespace=~\"$namespace\",pod=~\"$pod\",container!=\"\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Read", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "query": "label_values(kube_pod_info{}, namespace)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "pod", + "query": "label_values(kube_pod_info{namespace=\"$namespace\"}, pod)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Pod", + "uid": "rancher-pod-1", + "version": 8 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/workloads/rancher-workload-pods.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/workloads/rancher-workload-pods.json new file mode 100644 index 0000000000..92c0d24a6e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/workloads/rancher-workload-pods.json @@ -0,0 +1,652 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 28, + "iteration": 1618265214337, + "links": [], + "panels": [ + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(rate(container_cpu_cfs_throttled_seconds_total{namespace=~\"$namespace\",container=\"\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "CFS throttled ({{pod}})", + "refId": "A" + }, + { + "expr": "(sum(rate(container_cpu_system_seconds_total{namespace=~\"$namespace\",container=\"\"}[$__rate_interval])) by (pod) OR sum(rate(windows_container_cpu_usage_seconds_kernelmode{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "System ({{pod}})", + "refId": "B" + }, + { + "expr": "(sum(rate(container_cpu_usage_seconds_total{namespace=~\"$namespace\",container=\"\"}[$__rate_interval])) by (pod) OR sum(rate(windows_container_cpu_usage_seconds_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Total ({{pod}})", + "refId": "C" + }, + { + "expr": "(sum(rate(container_cpu_user_seconds_total{namespace=~\"$namespace\",container=\"\"}[$__rate_interval])) by (pod) OR sum(rate(windows_container_cpu_usage_seconds_usermode{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "User ({{pod}})", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "cpu", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(container_memory_working_set_bytes{namespace=~\"$namespace\",container=\"\"} OR windows_container_memory_usage_commit_bytes{namespace=~\"$namespace\"}) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "({{pod}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_receive_packets_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_receive_packets_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Receive Total ({{pod}})", + "refId": "A" + }, + { + "expr": "(sum(irate(container_network_transmit_packets_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_transmit_packets_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Transmit Total ({{pod}})", + "refId": "B" + }, + { + "expr": "(sum(irate(container_network_receive_packets_dropped_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_receive_packets_dropped_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Receive Dropped ({{pod}})", + "refId": "C" + }, + { + "expr": "(sum(irate(container_network_receive_errors_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Receive Errors ({{pod}})", + "refId": "D" + }, + { + "expr": "(sum(irate(container_network_transmit_errors_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Transmit Errors ({{pod}})", + "refId": "E" + }, + { + "expr": "(sum(irate(container_network_transmit_packets_dropped_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_transmit_packets_dropped_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Transmit Dropped ({{pod}})", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_receive_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_receive_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Receive Total ({{pod}})", + "refId": "A" + }, + { + "expr": "(sum(irate(container_network_transmit_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_transmit_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Transmit Total ({{pod}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(rate(container_fs_writes_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Write ({{pod}})", + "refId": "A" + }, + { + "expr": "(sum(rate(container_fs_reads_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"}", + "interval": "", + "legendFormat": "Read ({{pod}})", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "query": "query_result(kube_pod_info{namespace!=\"\"} * on(pod) group_right(namespace, created_by_kind, created_by_name) count({__name__=~\"container_.*|windows_container_.*\", pod!=\"\"}) by (pod))", + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*)\"/", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "kind", + "query": "query_result(kube_pod_info{namespace=\"$namespace\", created_by_kind!=\"\"} * on(pod) group_right(namespace, created_by_kind, created_by_name) count({__name__=~\"container_.*|windows_container_.*\", pod!=\"\"}) by (pod))", + "refresh": 2, + "regex": "/.*created_by_kind=\"([^\"]*)\"/", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "workload", + "query": "query_result(kube_pod_info{namespace=\"$namespace\", created_by_kind=\"$kind\", created_by_name!=\"\"} * on(pod) group_right(namespace, created_by_kind, created_by_name) count({__name__=~\"container_.*|windows_container_.*\", pod!=\"\"}) by (pod))", + "refresh": 2, + "regex": "/.*created_by_name=\"([^\"]*)\"/", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Workload (Pods)", + "uid": "rancher-workload-pods-1", + "version": 8 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/workloads/rancher-workload.json b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/workloads/rancher-workload.json new file mode 100644 index 0000000000..9f5317c2f0 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/rancher/workloads/rancher-workload.json @@ -0,0 +1,652 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 28, + "iteration": 1618265214337, + "links": [], + "panels": [ + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum((sum(rate(container_cpu_cfs_throttled_seconds_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "CFS throttled", + "refId": "A" + }, + { + "expr": "sum((sum(rate(container_cpu_system_seconds_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(rate(windows_container_cpu_usage_seconds_kernelmode{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "System", + "refId": "B" + }, + { + "expr": "sum((sum(rate(container_cpu_usage_seconds_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(rate(windows_container_cpu_usage_seconds_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Total", + "refId": "C" + }, + { + "expr": "sum((sum(rate(container_cpu_user_seconds_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(rate(windows_container_cpu_usage_seconds_usermode{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "User", + "refId": "D" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "cpu", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum((sum(container_memory_working_set_bytes{namespace=~\"$namespace\"} OR windows_container_memory_usage_commit_bytes{namespace=~\"$namespace\"}) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Total", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Utilization", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum((sum(irate(container_network_receive_packets_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_receive_packets_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Receive Total", + "refId": "A" + }, + { + "expr": "sum((sum(irate(container_network_transmit_packets_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_transmit_packets_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Transmit Total", + "refId": "B" + }, + { + "expr": "sum((sum(irate(container_network_receive_packets_dropped_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_receive_packets_dropped_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Receive Dropped", + "refId": "C" + }, + { + "expr": "sum((sum(irate(container_network_receive_errors_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Receive Errors", + "refId": "D" + }, + { + "expr": "sum((sum(irate(container_network_transmit_errors_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Transmit Errors", + "refId": "E" + }, + { + "expr": "sum((sum(irate(container_network_transmit_packets_dropped_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_transmit_packets_dropped_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Transmit Dropped", + "refId": "F" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum((sum(irate(container_network_receive_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_receive_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Receive Total", + "refId": "A" + }, + { + "expr": "sum((sum(irate(container_network_transmit_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod) OR sum(irate(windows_container_network_transmit_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Transmit Total", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "{{pod}}": "#3797d5" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 7 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum((sum(rate(container_fs_writes_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Write", + "refId": "A" + }, + { + "expr": "sum((sum(rate(container_fs_reads_bytes_total{namespace=~\"$namespace\"}[$__rate_interval])) by (pod)) * on(pod) kube_pod_info{namespace=~\"$namespace\", created_by_kind=\"$kind\", created_by_name=\"$workload\"})", + "interval": "", + "legendFormat": "Read", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "query": "query_result(kube_pod_info{namespace!=\"\"} * on(pod) group_right(namespace, created_by_kind, created_by_name) count({__name__=~\"container_.*|windows_container_.*\", pod!=\"\"}) by (pod))", + "refresh": 2, + "regex": "/.*namespace=\"([^\"]*)\"/", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "kind", + "query": "query_result(kube_pod_info{namespace=\"$namespace\", created_by_kind!=\"\"} * on(pod) group_right(namespace, created_by_kind, created_by_name) count({__name__=~\"container_.*|windows_container_.*\", pod!=\"\"}) by (pod))", + "refresh": 2, + "regex": "/.*created_by_kind=\"([^\"]*)\"/", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "workload", + "query": "query_result(kube_pod_info{namespace=\"$namespace\", created_by_kind=\"$kind\", created_by_name!=\"\"} * on(pod) group_right(namespace, created_by_kind, created_by_name) count({__name__=~\"container_.*|windows_container_.*\", pod!=\"\"}) by (pod))", + "refresh": 2, + "regex": "/.*created_by_name=\"([^\"]*)\"/", + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Rancher / Workload", + "uid": "rancher-workload-1", + "version": 8 +} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/files/upgrade/scripts/delete-workloads-with-old-labels.sh b/charts/rancher-monitoring/105.1.3+up61.3.2/files/upgrade/scripts/delete-workloads-with-old-labels.sh new file mode 100644 index 0000000000..89431e7132 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/files/upgrade/scripts/delete-workloads-with-old-labels.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -e +set -x + +# node-exporter +kubectl delete daemonset -l app=prometheus-node-exporter,release=rancher-monitoring --ignore-not-found=true + +# prometheus-adapter +kubectl delete deployments -l app=prometheus-adapter,release=rancher-monitoring --ignore-not-found=true + +# kube-state-metrics +kubectl delete deployments -l app.kubernetes.io/instance=rancher-monitoring,app.kubernetes.io/name=kube-state-metrics --cascade=orphan --ignore-not-found=true +kubectl delete statefulsets -l app.kubernetes.io/instance=rancher-monitoring,app.kubernetes.io/name=kube-state-metrics --cascade=orphan --ignore-not-found=true diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/NOTES.txt b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/NOTES.txt new file mode 100644 index 0000000000..371f3ae398 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/NOTES.txt @@ -0,0 +1,4 @@ +{{ $.Chart.Name }} has been installed. Check its status by running: + kubectl --namespace {{ template "kube-prometheus-stack.namespace" . }} get pods -l "release={{ $.Release.Name }}" + +Visit https://github.com/prometheus-operator/kube-prometheus for instructions on how to create & configure Alertmanager and Prometheus instances using the Operator. diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/_helpers.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/_helpers.tpl new file mode 100644 index 0000000000..2e964669f2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/_helpers.tpl @@ -0,0 +1,472 @@ +# Rancher +{{- define "system_default_registry" -}} +{{- if .Values.global.cattle.systemDefaultRegistry -}} +{{- printf "%s/" .Values.global.cattle.systemDefaultRegistry -}} +{{- end -}} +{{- end -}} + +{{- define "monitoring_registry" -}} + {{- $temp_registry := (include "system_default_registry" .) -}} + {{- if $temp_registry -}} + {{- trimSuffix "/" $temp_registry -}} + {{- else -}} + {{- .Values.global.imageRegistry -}} + {{- end -}} +{{- end -}} + +{{/* +https://github.com/helm/helm/issues/4535#issuecomment-477778391 +Usage: {{ include "call-nested" (list . "SUBCHART_NAME" "TEMPLATE") }} +e.g. {{ include "call-nested" (list . "grafana" "grafana.fullname") }} +*/}} +{{- define "call-nested" }} +{{- $dot := index . 0 }} +{{- $subchart := index . 1 | splitList "." }} +{{- $template := index . 2 }} +{{- $values := $dot.Values }} +{{- range $subchart }} +{{- $values = index $values . }} +{{- end }} +{{- include $template (dict "Chart" (dict "Name" (last $subchart)) "Values" $values "Release" $dot.Release "Capabilities" $dot.Capabilities) }} +{{- end }} + +# Special Exporters +{{- define "exporter.kubeEtcd.enabled" -}} +{{- if or .Values.kubeEtcd.enabled .Values.rkeEtcd.enabled .Values.kubeAdmEtcd.enabled .Values.rke2Etcd.enabled -}} +"true" +{{- end -}} +{{- end }} + +{{- define "exporter.kubeControllerManager.enabled" -}} +{{- if or .Values.kubeControllerManager.enabled .Values.rkeControllerManager.enabled .Values.k3sServer.enabled .Values.kubeAdmControllerManager.enabled .Values.rke2ControllerManager.enabled -}} +"true" +{{- end -}} +{{- end }} + +{{- define "exporter.kubeScheduler.enabled" -}} +{{- if or .Values.kubeScheduler.enabled .Values.rkeScheduler.enabled .Values.k3sServer.enabled .Values.kubeAdmScheduler.enabled .Values.rke2Scheduler.enabled -}} +"true" +{{- end -}} +{{- end }} + +{{- define "exporter.kubeProxy.enabled" -}} +{{- if or .Values.kubeProxy.enabled .Values.rkeProxy.enabled .Values.k3sServer.enabled .Values.kubeAdmProxy.enabled .Values.rke2Proxy.enabled -}} +"true" +{{- end -}} +{{- end }} + +{{- define "exporter.kubelet.enabled" -}} +{{- if or .Values.kubelet.enabled .Values.hardenedKubelet.enabled .Values.k3sServer.enabled -}} +"true" +{{- end -}} +{{- end }} + +{{- define "exporter.kubeControllerManager.jobName" -}} +{{- if .Values.k3sServer.enabled -}} +k3s-server +{{- else -}} +kube-controller-manager +{{- end -}} +{{- end }} + +{{- define "exporter.kubeScheduler.jobName" -}} +{{- if .Values.k3sServer.enabled -}} +k3s-server +{{- else -}} +kube-scheduler +{{- end -}} +{{- end }} + +{{- define "exporter.kubeProxy.jobName" -}} +{{- if .Values.k3sServer.enabled -}} +k3s-server +{{- else -}} +kube-proxy +{{- end -}} +{{- end }} + +{{- define "exporter.kubelet.jobName" -}} +{{- if .Values.k3sServer.enabled -}} +k3s-server +{{- else -}} +kubelet +{{- end -}} +{{- end }} + +{{- define "kubelet.serviceMonitor.resourcePath" -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if not (eq .Values.kubelet.serviceMonitor.resourcePath "/metrics/resource/v1alpha1") -}} +{{ .Values.kubelet.serviceMonitor.resourcePath }} +{{- else if semverCompare ">=1.20.0-0" $kubeTargetVersion -}} +/metrics/resource +{{- else -}} +/metrics/resource/v1alpha1 +{{- end -}} +{{- end }} + +{{- define "rancher.serviceMonitor.selector" -}} +{{- if .Values.rancherMonitoring.selector }} +{{ .Values.rancherMonitoring.selector | toYaml }} +{{- else }} +{{- $rancherDeployment := (lookup "apps/v1" "Deployment" "cattle-system" "rancher") }} +{{- if $rancherDeployment }} +matchLabels: + app: rancher + chart: {{ index $rancherDeployment.metadata.labels "chart" }} + release: rancher +{{- end }} +{{- end }} +{{- end }} + +# Windows Support + +{{/* +Windows cluster will add default taint for linux nodes, +add below linux tolerations to workloads could be scheduled to those linux nodes +*/}} + +{{- define "linux-node-tolerations" -}} +- key: "cattle.io/os" + value: "linux" + effect: "NoSchedule" + operator: "Equal" +{{- end -}} + +{{- define "linux-node-selector" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +beta.kubernetes.io/os: linux +{{- else -}} +kubernetes.io/os: linux +{{- end -}} +{{- end -}} + +# Prometheus Operator + +{{/* vim: set filetype=mustache: */}} +{{/* Expand the name of the chart. This is suffixed with -alertmanager, which means subtract 13 from longest 63 available */}} +{{- define "kube-prometheus-stack.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 50 | 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. +The components in this chart create additional resources that expand the longest created name strings. +The longest name that gets created adds and extra 37 characters, so truncation should be 63-35=26. +*/}} +{{- define "kube-prometheus-stack.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 26 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 26 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 26 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* Fullname suffixed with -operator */}} +{{/* Adding 9 to 26 truncation of kube-prometheus-stack.fullname */}} +{{- define "kube-prometheus-stack.operator.fullname" -}} +{{- if .Values.prometheusOperator.fullnameOverride -}} +{{- .Values.prometheusOperator.fullnameOverride | trunc 35 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-operator" (include "kube-prometheus-stack.fullname" .) -}} +{{- end }} +{{- end }} + +{{/* Prometheus custom resource instance name */}} +{{- define "kube-prometheus-stack.prometheus.crname" -}} +{{- if .Values.cleanPrometheusOperatorObjectNames }} +{{- include "kube-prometheus-stack.fullname" . }} +{{- else }} +{{- print (include "kube-prometheus-stack.fullname" .) "-prometheus" }} +{{- end }} +{{- end }} + +{{/* Prometheus apiVersion for networkpolicy */}} +{{- define "kube-prometheus-stack.prometheus.networkPolicy.apiVersion" -}} +{{- print "networking.k8s.io/v1" -}} +{{- end }} + +{{/* Alertmanager custom resource instance name */}} +{{- define "kube-prometheus-stack.alertmanager.crname" -}} +{{- if .Values.cleanPrometheusOperatorObjectNames }} +{{- include "kube-prometheus-stack.fullname" . }} +{{- else }} +{{- print (include "kube-prometheus-stack.fullname" .) "-alertmanager" -}} +{{- end }} +{{- end }} + +{{/* ThanosRuler custom resource instance name */}} +{{/* Subtracting 1 from 26 truncation of kube-prometheus-stack.fullname */}} +{{- define "kube-prometheus-stack.thanosRuler.crname" -}} +{{- if .Values.cleanPrometheusOperatorObjectNames }} +{{- include "kube-prometheus-stack.fullname" . }} +{{- else }} +{{- print (include "kube-prometheus-stack.fullname" . | trunc 25 | trimSuffix "-") "-thanos-ruler" -}} +{{- end }} +{{- end }} + +{{/* Shortened name suffixed with thanos-ruler */}} +{{- define "kube-prometheus-stack.thanosRuler.name" -}} +{{- default (printf "%s-thanos-ruler" (include "kube-prometheus-stack.name" .)) .Values.thanosRuler.name -}} +{{- end }} + + +{{/* Create chart name and version as used by the chart label. */}} +{{- define "kube-prometheus-stack.chartref" -}} +{{- replace "+" "_" .Chart.Version | printf "%s-%s" .Chart.Name -}} +{{- end }} + +{{/* Generate basic labels */}} +{{- define "kube-prometheus-stack.labels" }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/version: "{{ replace "+" "_" .Chart.Version }}" +app.kubernetes.io/part-of: {{ template "kube-prometheus-stack.name" . }} +chart: {{ template "kube-prometheus-stack.chartref" . }} +release: {{ $.Release.Name | quote }} +heritage: {{ $.Release.Service | quote }} +{{- if .Values.commonLabels}} +{{ toYaml .Values.commonLabels }} +{{- end }} +{{- end }} + +{{/* Create the name of kube-prometheus-stack service account to use */}} +{{- define "kube-prometheus-stack.operator.serviceAccountName" -}} +{{- if .Values.prometheusOperator.serviceAccount.create -}} + {{ default (include "kube-prometheus-stack.operator.fullname" .) .Values.prometheusOperator.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.prometheusOperator.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* Create the name of kube-prometheus-stack service account to use */}} +{{- define "kube-prometheus-stack.operator.admissionWebhooks.serviceAccountName" -}} +{{- if .Values.prometheusOperator.serviceAccount.create -}} + {{ default (printf "%s-webhook" (include "kube-prometheus-stack.operator.fullname" .)) .Values.prometheusOperator.admissionWebhooks.deployment.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.prometheusOperator.admissionWebhooks.deployment.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* Create the name of prometheus service account to use */}} +{{- define "kube-prometheus-stack.prometheus.serviceAccountName" -}} +{{- if .Values.prometheus.serviceAccount.create -}} + {{ default (print (include "kube-prometheus-stack.fullname" .) "-prometheus") .Values.prometheus.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.prometheus.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* Create the name of alertmanager service account to use */}} +{{- define "kube-prometheus-stack.alertmanager.serviceAccountName" -}} +{{- if .Values.alertmanager.serviceAccount.create -}} + {{ default (print (include "kube-prometheus-stack.fullname" .) "-alertmanager") .Values.alertmanager.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.alertmanager.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* Create the name of thanosRuler service account to use */}} +{{- define "kube-prometheus-stack.thanosRuler.serviceAccountName" -}} +{{- if .Values.thanosRuler.serviceAccount.create -}} + {{ default (include "kube-prometheus-stack.thanosRuler.name" .) .Values.thanosRuler.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.thanosRuler.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "kube-prometheus-stack.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +Use the grafana namespace override for multi-namespace deployments in combined charts +*/}} +{{- define "kube-prometheus-stack-grafana.namespace" -}} + {{- if .Values.grafana.namespaceOverride -}} + {{- .Values.grafana.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +Allow kube-state-metrics job name to be overridden +*/}} +{{- define "kube-prometheus-stack-kube-state-metrics.name" -}} + {{- if index .Values "kube-state-metrics" "nameOverride" -}} + {{- index .Values "kube-state-metrics" "nameOverride" -}} + {{- else -}} + {{- print "kube-state-metrics" -}} + {{- end -}} +{{- end -}} + +{{/* +Use the kube-state-metrics namespace override for multi-namespace deployments in combined charts +*/}} +{{- define "kube-prometheus-stack-kube-state-metrics.namespace" -}} + {{- if index .Values "kube-state-metrics" "namespaceOverride" -}} + {{- index .Values "kube-state-metrics" "namespaceOverride" -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +Use the prometheus-node-exporter namespace override for multi-namespace deployments in combined charts +*/}} +{{- define "kube-prometheus-stack-prometheus-node-exporter.namespace" -}} + {{- if index .Values "prometheus-node-exporter" "namespaceOverride" -}} + {{- index .Values "prometheus-node-exporter" "namespaceOverride" -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* Allow KubeVersion to be overridden. */}} +{{- define "kube-prometheus-stack.kubeVersion" -}} + {{- default .Capabilities.KubeVersion.Version .Values.kubeVersionOverride -}} +{{- end -}} + +{{/* Get Ingress API Version */}} +{{- define "kube-prometheus-stack.ingress.apiVersion" -}} + {{- if and (.Capabilities.APIVersions.Has "networking.k8s.io/v1") (semverCompare ">= 1.19-0" (include "kube-prometheus-stack.kubeVersion" .)) -}} + {{- print "networking.k8s.io/v1" -}} + {{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}} + {{- print "networking.k8s.io/v1beta1" -}} + {{- else -}} + {{- print "extensions/v1beta1" -}} + {{- end -}} +{{- end -}} + +{{/* Check Ingress stability */}} +{{- define "kube-prometheus-stack.ingress.isStable" -}} + {{- eq (include "kube-prometheus-stack.ingress.apiVersion" .) "networking.k8s.io/v1" -}} +{{- end -}} + +{{/* Check Ingress supports pathType */}} +{{/* pathType was added to networking.k8s.io/v1beta1 in Kubernetes 1.18 */}} +{{- define "kube-prometheus-stack.ingress.supportsPathType" -}} + {{- or (eq (include "kube-prometheus-stack.ingress.isStable" .) "true") (and (eq (include "kube-prometheus-stack.ingress.apiVersion" .) "networking.k8s.io/v1beta1") (semverCompare ">= 1.18-0" (include "kube-prometheus-stack.kubeVersion" .))) -}} +{{- end -}} + +{{/* Get Policy API Version */}} +{{- define "kube-prometheus-stack.pdb.apiVersion" -}} + {{- if and (.Capabilities.APIVersions.Has "policy/v1") (semverCompare ">= 1.21-0" (include "kube-prometheus-stack.kubeVersion" .)) -}} + {{- print "policy/v1" -}} + {{- else -}} + {{- print "policy/v1beta1" -}} + {{- end -}} + {{- end -}} + +{{/* Get value based on current Kubernetes version */}} +{{- define "kube-prometheus-stack.kubeVersionDefaultValue" -}} + {{- $values := index . 0 -}} + {{- $kubeVersion := index . 1 -}} + {{- $old := index . 2 -}} + {{- $new := index . 3 -}} + {{- $default := index . 4 -}} + {{- if kindIs "invalid" $default -}} + {{- if semverCompare $kubeVersion (include "kube-prometheus-stack.kubeVersion" $values) -}} + {{- print $new -}} + {{- else -}} + {{- print $old -}} + {{- end -}} + {{- else -}} + {{- print $default }} + {{- end -}} +{{- end -}} + +{{/* Get value for kube-controller-manager depending on insecure scraping availability */}} +{{- define "kube-prometheus-stack.kubeControllerManager.insecureScrape" -}} + {{- $values := index . 0 -}} + {{- $insecure := index . 1 -}} + {{- $secure := index . 2 -}} + {{- $userValue := index . 3 -}} + {{- include "kube-prometheus-stack.kubeVersionDefaultValue" (list $values ">= 1.22-0" $insecure $secure $userValue) -}} +{{- end -}} + +{{/* Get value for kube-scheduler depending on insecure scraping availability */}} +{{- define "kube-prometheus-stack.kubeScheduler.insecureScrape" -}} + {{- $values := index . 0 -}} + {{- $insecure := index . 1 -}} + {{- $secure := index . 2 -}} + {{- $userValue := index . 3 -}} + {{- include "kube-prometheus-stack.kubeVersionDefaultValue" (list $values ">= 1.23-0" $insecure $secure $userValue) -}} +{{- end -}} + +{{/* Sets default scrape limits for servicemonitor */}} +{{- define "servicemonitor.scrapeLimits" -}} +{{- with .sampleLimit }} +sampleLimit: {{ . }} +{{- end }} +{{- with .targetLimit }} +targetLimit: {{ . }} +{{- end }} +{{- with .labelLimit }} +labelLimit: {{ . }} +{{- end }} +{{- with .labelNameLengthLimit }} +labelNameLengthLimit: {{ . }} +{{- end }} +{{- with .labelValueLengthLimit }} +labelValueLengthLimit: {{ . }} +{{- end }} +{{- end -}} + +{{/* +To help compatibility with other charts which use global.imagePullSecrets. +Allow either an array of {name: pullSecret} maps (k8s-style), or an array of strings (more common helm-style). +global: + imagePullSecrets: + - name: pullSecret1 + - name: pullSecret2 + +or + +global: + imagePullSecrets: + - pullSecret1 + - pullSecret2 +*/}} +{{- define "kube-prometheus-stack.imagePullSecrets" -}} +{{- range .Values.global.imagePullSecrets }} + {{- if eq (typeOf .) "map[string]interface {}" }} +- {{ toYaml . | trim }} + {{- else }} +- name: {{ . }} + {{- end }} +{{- end }} +{{- end -}} + +{{- define "kube-prometheus-stack.operator.admission-webhook.dnsNames" }} +{{- $fullname := include "kube-prometheus-stack.operator.fullname" . }} +{{- $namespace := include "kube-prometheus-stack.namespace" . }} +{{- $fullname }} +{{ $fullname }}.{{ $namespace }}.svc +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.enabled }} +{{ $fullname }}-webhook +{{ $fullname }}-webhook.{{ $namespace }}.svc +{{- end }} +{{- end }} + +{{- define "rke2-ingress-nginx.namespace" -}} + {{- if .Values.rke2IngressNginx.namespaceOverride -}} + {{- .Values.rke2IngressNginx.namespaceOverride -}} + {{- else -}} + {{- print "kube-system" -}} + {{- end -}} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/alertmanager.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/alertmanager.yaml new file mode 100644 index 0000000000..fdc9a8af61 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/alertmanager.yaml @@ -0,0 +1,195 @@ +{{- if .Values.alertmanager.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: Alertmanager +metadata: + name: {{ template "kube-prometheus-stack.alertmanager.crname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.alertmanager.annotations }} + annotations: +{{ toYaml .Values.alertmanager.annotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.alertmanager.alertmanagerSpec.image }} + {{- $registry := include "monitoring_registry" . | default .Values.alertmanager.alertmanagerSpec.image.registry }} + {{- if and .Values.alertmanager.alertmanagerSpec.image.tag .Values.alertmanager.alertmanagerSpec.image.sha }} + image: "{{ $registry }}/{{ .Values.alertmanager.alertmanagerSpec.image.repository }}:{{ .Values.alertmanager.alertmanagerSpec.image.tag }}@sha256:{{ .Values.alertmanager.alertmanagerSpec.image.sha }}" + {{- else if .Values.alertmanager.alertmanagerSpec.image.sha }} + image: "{{ $registry }}/{{ .Values.alertmanager.alertmanagerSpec.image.repository }}@sha256:{{ .Values.alertmanager.alertmanagerSpec.image.sha }}" + {{- else if .Values.alertmanager.alertmanagerSpec.image.tag }} + image: "{{ $registry }}/{{ .Values.alertmanager.alertmanagerSpec.image.repository }}:{{ .Values.alertmanager.alertmanagerSpec.image.tag }}" + {{- else }} + image: "{{ $registry }}/{{ .Values.alertmanager.alertmanagerSpec.image.repository }}" + {{- end }} + version: {{ default .Values.alertmanager.alertmanagerSpec.image.tag .Values.alertmanager.alertmanagerSpec.version }} + {{- if .Values.alertmanager.alertmanagerSpec.image.sha }} + sha: {{ .Values.alertmanager.alertmanagerSpec.image.sha }} + {{- end }} +{{- end }} + replicas: {{ .Values.alertmanager.alertmanagerSpec.replicas }} + listenLocal: {{ .Values.alertmanager.alertmanagerSpec.listenLocal }} + serviceAccountName: {{ template "kube-prometheus-stack.alertmanager.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.alertmanager.alertmanagerSpec.automountServiceAccountToken }} +{{- if .Values.alertmanager.alertmanagerSpec.externalUrl }} + externalUrl: "{{ tpl .Values.alertmanager.alertmanagerSpec.externalUrl . }}" +{{- else if and .Values.alertmanager.ingress.enabled .Values.alertmanager.ingress.hosts }} + externalUrl: "http://{{ tpl (index .Values.alertmanager.ingress.hosts 0) . }}{{ .Values.alertmanager.alertmanagerSpec.routePrefix }}" +{{- else if not (or (kindIs "invalid" .Values.global.cattle.url) (kindIs "invalid" .Values.global.cattle.clusterId)) }} + externalUrl: "{{ .Values.global.cattle.url }}/k8s/clusters/{{ .Values.global.cattle.clusterId }}/api/v1/namespaces/{{ .Values.namespaceOverride }}/services/http:{{ template "kube-prometheus-stack.fullname" . }}-alertmanager:{{ .Values.alertmanager.service.port }}/proxy" +{{- else }} + externalUrl: http://{{ template "kube-prometheus-stack.fullname" . }}-alertmanager.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.alertmanager.service.port }} +{{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 4 }} +{{- if .Values.alertmanager.alertmanagerSpec.nodeSelector }} +{{ toYaml .Values.alertmanager.alertmanagerSpec.nodeSelector | indent 4 }} +{{- end }} + paused: {{ .Values.alertmanager.alertmanagerSpec.paused }} + logFormat: {{ .Values.alertmanager.alertmanagerSpec.logFormat | quote }} + logLevel: {{ .Values.alertmanager.alertmanagerSpec.logLevel | quote }} + retention: {{ .Values.alertmanager.alertmanagerSpec.retention | quote }} + {{- with .Values.alertmanager.enableFeatures }} + enableFeatures: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.secrets }} + secrets: +{{ toYaml .Values.alertmanager.alertmanagerSpec.secrets | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.configSecret }} + configSecret: {{ .Values.alertmanager.alertmanagerSpec.configSecret }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.configMaps }} + configMaps: +{{ toYaml .Values.alertmanager.alertmanagerSpec.configMaps | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.alertmanagerConfigSelector }} + alertmanagerConfigSelector: +{{ tpl (toYaml .Values.alertmanager.alertmanagerSpec.alertmanagerConfigSelector | indent 4) . }} +{{ else }} + alertmanagerConfigSelector: {} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.alertmanagerConfigNamespaceSelector }} + alertmanagerConfigNamespaceSelector: +{{ tpl (toYaml .Values.alertmanager.alertmanagerSpec.alertmanagerConfigNamespaceSelector | indent 4) . }} +{{ else }} + alertmanagerConfigNamespaceSelector: {} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.web }} + web: +{{ toYaml .Values.alertmanager.alertmanagerSpec.web | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.alertmanagerConfiguration }} + alertmanagerConfiguration: +{{ toYaml .Values.alertmanager.alertmanagerSpec.alertmanagerConfiguration | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.alertmanagerConfigMatcherStrategy }} + alertmanagerConfigMatcherStrategy: +{{ toYaml .Values.alertmanager.alertmanagerSpec.alertmanagerConfigMatcherStrategy | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.resources }} + resources: +{{ toYaml .Values.alertmanager.alertmanagerSpec.resources | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.routePrefix }} + routePrefix: "{{ .Values.alertmanager.alertmanagerSpec.routePrefix }}" +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.securityContext }} + securityContext: +{{ toYaml .Values.alertmanager.alertmanagerSpec.securityContext | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.storage }} + storage: +{{ tpl (toYaml .Values.alertmanager.alertmanagerSpec.storage | indent 4) . }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.podMetadata }} + podMetadata: +{{ toYaml .Values.alertmanager.alertmanagerSpec.podMetadata | indent 4 }} +{{- end }} +{{- if or .Values.alertmanager.alertmanagerSpec.podAntiAffinity .Values.alertmanager.alertmanagerSpec.affinity }} + affinity: +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.affinity }} +{{ toYaml .Values.alertmanager.alertmanagerSpec.affinity | indent 4 }} +{{- end }} +{{- if eq .Values.alertmanager.alertmanagerSpec.podAntiAffinity "hard" }} + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: {{ .Values.alertmanager.alertmanagerSpec.podAntiAffinityTopologyKey }} + labelSelector: + matchExpressions: + - {key: app.kubernetes.io/name, operator: In, values: [alertmanager]} + - {key: alertmanager, operator: In, values: [{{ template "kube-prometheus-stack.alertmanager.crname" . }}]} +{{- else if eq .Values.alertmanager.alertmanagerSpec.podAntiAffinity "soft" }} + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: {{ .Values.alertmanager.alertmanagerSpec.podAntiAffinityTopologyKey }} + labelSelector: + matchExpressions: + - {key: app.kubernetes.io/name, operator: In, values: [alertmanager]} + - {key: alertmanager, operator: In, values: [{{ template "kube-prometheus-stack.alertmanager.crname" . }}]} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 4 }} +{{- if .Values.alertmanager.alertmanagerSpec.tolerations }} +{{ toYaml .Values.alertmanager.alertmanagerSpec.tolerations | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.alertmanager.alertmanagerSpec.topologySpreadConstraints | indent 4 }} +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.containers }} + containers: +{{ toYaml .Values.alertmanager.alertmanagerSpec.containers | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.initContainers }} + initContainers: +{{ toYaml .Values.alertmanager.alertmanagerSpec.initContainers | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.priorityClassName }} + priorityClassName: {{.Values.alertmanager.alertmanagerSpec.priorityClassName }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.additionalPeers }} + additionalPeers: +{{ toYaml .Values.alertmanager.alertmanagerSpec.additionalPeers | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.volumes }} + volumes: +{{ toYaml .Values.alertmanager.alertmanagerSpec.volumes | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.volumeMounts }} + volumeMounts: +{{ toYaml .Values.alertmanager.alertmanagerSpec.volumeMounts | indent 4 }} +{{- end }} + portName: {{ .Values.alertmanager.alertmanagerSpec.portName }} +{{- if .Values.alertmanager.alertmanagerSpec.clusterAdvertiseAddress }} + clusterAdvertiseAddress: {{ .Values.alertmanager.alertmanagerSpec.clusterAdvertiseAddress }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.clusterGossipInterval }} + clusterGossipInterval: {{ .Values.alertmanager.alertmanagerSpec.clusterGossipInterval }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.clusterPeerTimeout }} + clusterPeerTimeout: {{ .Values.alertmanager.alertmanagerSpec.clusterPeerTimeout }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.clusterPushpullInterval }} + clusterPushpullInterval: {{ .Values.alertmanager.alertmanagerSpec.clusterPushpullInterval }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.forceEnableClusterMode }} + forceEnableClusterMode: {{ .Values.alertmanager.alertmanagerSpec.forceEnableClusterMode }} +{{- end }} +{{- if .Values.alertmanager.alertmanagerSpec.minReadySeconds }} + minReadySeconds: {{ .Values.alertmanager.alertmanagerSpec.minReadySeconds }} +{{- end }} +{{- with .Values.alertmanager.alertmanagerSpec.additionalConfig }} + {{- tpl (toYaml .) $ | nindent 2 }} +{{- end }} +{{- with .Values.alertmanager.alertmanagerSpec.additionalConfigString }} + {{- tpl . $ | nindent 2 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/extrasecret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/extrasecret.yaml new file mode 100644 index 0000000000..ecd8f47021 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/extrasecret.yaml @@ -0,0 +1,20 @@ +{{- if .Values.alertmanager.extraSecret.data -}} +{{- $secretName := printf "alertmanager-%s-extra" (include "kube-prometheus-stack.fullname" . ) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default $secretName .Values.alertmanager.extraSecret.name }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- if .Values.alertmanager.extraSecret.annotations }} + annotations: +{{ toYaml .Values.alertmanager.extraSecret.annotations | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager + app.kubernetes.io/component: alertmanager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: +{{- range $key, $val := .Values.alertmanager.extraSecret.data }} + {{ $key }}: {{ $val | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/ingress.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/ingress.yaml new file mode 100644 index 0000000000..be9f5aa279 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/ingress.yaml @@ -0,0 +1,78 @@ +{{- if and .Values.alertmanager.enabled .Values.alertmanager.ingress.enabled }} +{{- $pathType := .Values.alertmanager.ingress.pathType | default "ImplementationSpecific" }} +{{- $serviceName := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "alertmanager" }} +{{- $backendServiceName := .Values.alertmanager.ingress.serviceName | default (printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "alertmanager") }} +{{- $servicePort := .Values.alertmanager.ingress.servicePort | default .Values.alertmanager.service.port -}} +{{- $routePrefix := list .Values.alertmanager.alertmanagerSpec.routePrefix }} +{{- $paths := .Values.alertmanager.ingress.paths | default $routePrefix -}} +{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}} +{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}} +apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ $serviceName }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- if .Values.alertmanager.ingress.annotations }} + annotations: + {{- tpl (toYaml .Values.alertmanager.ingress.annotations) . | nindent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager +{{- if .Values.alertmanager.ingress.labels }} +{{ toYaml .Values.alertmanager.ingress.labels | indent 4 }} +{{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + {{- if $apiIsStable }} + {{- if .Values.alertmanager.ingress.ingressClassName }} + ingressClassName: {{ .Values.alertmanager.ingress.ingressClassName }} + {{- end }} + {{- end }} + rules: + {{- if .Values.alertmanager.ingress.hosts }} + {{- range $host := .Values.alertmanager.ingress.hosts }} + - host: {{ tpl $host $ | quote }} + http: + paths: + {{- range $p := $paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ $backendServiceName }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ $backendServiceName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end -}} + {{- end -}} + {{- else }} + - http: + paths: + {{- range $p := $paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ $backendServiceName }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ $backendServiceName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end -}} + {{- end -}} + {{- if .Values.alertmanager.ingress.tls }} + tls: +{{ tpl (toYaml .Values.alertmanager.ingress.tls | indent 4) . }} + {{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/ingressperreplica.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/ingressperreplica.yaml new file mode 100644 index 0000000000..b2e00a4162 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/ingressperreplica.yaml @@ -0,0 +1,67 @@ +{{- if and .Values.alertmanager.enabled .Values.alertmanager.servicePerReplica.enabled .Values.alertmanager.ingressPerReplica.enabled }} +{{- $pathType := .Values.alertmanager.ingressPerReplica.pathType | default "" }} +{{- $count := .Values.alertmanager.alertmanagerSpec.replicas | int -}} +{{- $servicePort := .Values.alertmanager.service.port -}} +{{- $ingressValues := .Values.alertmanager.ingressPerReplica -}} +{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}} +{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}} +apiVersion: v1 +kind: List +metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-ingressperreplica + namespace: {{ template "kube-prometheus-stack.namespace" . }} +items: +{{ range $i, $e := until $count }} + - kind: Ingress + apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" $ }} + metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-{{ $i }} + namespace: {{ template "kube-prometheus-stack.namespace" $ }} + labels: + app: {{ include "kube-prometheus-stack.name" $ }}-alertmanager + {{ include "kube-prometheus-stack.labels" $ | indent 8 }} + {{- if $ingressValues.labels }} +{{ toYaml $ingressValues.labels | indent 8 }} + {{- end }} + {{- if $ingressValues.annotations }} + annotations: + {{- tpl (toYaml $ingressValues.annotations) $ | nindent 8 }} + {{- end }} + spec: + {{- if $apiIsStable }} + {{- if $ingressValues.ingressClassName }} + ingressClassName: {{ $ingressValues.ingressClassName }} + {{- end }} + {{- end }} + rules: + - host: {{ $ingressValues.hostPrefix }}-{{ $i }}.{{ $ingressValues.hostDomain }} + http: + paths: + {{- range $p := $ingressValues.paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-{{ $i }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-{{ $i }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end -}} + {{- if or $ingressValues.tlsSecretName $ingressValues.tlsSecretPerReplica.enabled }} + tls: + - hosts: + - {{ $ingressValues.hostPrefix }}-{{ $i }}.{{ $ingressValues.hostDomain }} + {{- if $ingressValues.tlsSecretPerReplica.enabled }} + secretName: {{ $ingressValues.tlsSecretPerReplica.prefix }}-{{ $i }} + {{- else }} + secretName: {{ $ingressValues.tlsSecretName }} + {{- end }} + {{- end }} +{{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/podDisruptionBudget.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/podDisruptionBudget.yaml new file mode 100644 index 0000000000..b183403125 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/podDisruptionBudget.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.alertmanager.enabled .Values.alertmanager.podDisruptionBudget.enabled }} +apiVersion: {{ include "kube-prometheus-stack.pdb.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + {{- if .Values.alertmanager.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.alertmanager.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.alertmanager.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.alertmanager.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + app.kubernetes.io/name: alertmanager + alertmanager: {{ template "kube-prometheus-stack.alertmanager.crname" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp-role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp-role.yaml new file mode 100644 index 0000000000..e8da52e0f4 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp-role.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.alertmanager.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +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-prometheus-stack.fullname" . }}-alertmanager +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp-rolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp-rolebinding.yaml new file mode 100644 index 0000000000..71a8ec41dc --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp-rolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.alertmanager.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager +subjects: + - kind: ServiceAccount + name: {{ template "kube-prometheus-stack.alertmanager.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp.yaml new file mode 100644 index 0000000000..5a940afab6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/psp.yaml @@ -0,0 +1,47 @@ +{{- if and .Values.alertmanager.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager +{{- if .Values.global.rbac.pspAnnotations }} + annotations: +{{ toYaml .Values.global.rbac.pspAnnotations | indent 4 }} +{{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + privileged: false + # 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: + # Allow adding the root group. + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Allow adding the root group. + - min: 0 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/secret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/secret.yaml new file mode 100644 index 0000000000..d4c397fa43 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/secret.yaml @@ -0,0 +1,37 @@ +{{- if and (.Values.alertmanager.enabled) (not .Values.alertmanager.alertmanagerSpec.useExistingSecret) }} +{{/* This file is applied when the operation is helm install and the target secret does not exist. */}} +{{- $secretName := (printf "alertmanager-%s" (include "kube-prometheus-stack.alertmanager.crname" .)) }} +{{- if or (not (lookup "v1" "Secret" (include "kube-prometheus-stack.namespace" .) $secretName)) (eq .Values.alertmanager.secret.recreateIfExists true) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": pre-install, pre-upgrade + "helm.sh/hook-weight": "3" + "helm.sh/resource-policy": keep +{{- if .Values.alertmanager.secret.annotations }} + annotations: +{{ toYaml .Values.alertmanager.secret.annotations | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: +{{- if .Values.alertmanager.tplConfig }} +{{- if .Values.alertmanager.stringConfig }} + alertmanager.yaml: {{ tpl (.Values.alertmanager.stringConfig) . | b64enc | quote }} +{{- else if eq (typeOf .Values.alertmanager.config) "string" }} + alertmanager.yaml: {{ tpl (.Values.alertmanager.config) . | b64enc | quote }} +{{- else }} + alertmanager.yaml: {{ tpl (toYaml .Values.alertmanager.config) . | b64enc | quote }} +{{- end }} +{{- else }} + alertmanager.yaml: {{ toYaml .Values.alertmanager.config | b64enc | quote }} +{{- end }} +{{- range $key, $val := .Values.alertmanager.templateFiles }} + {{ $key }}: {{ $val | b64enc | quote }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/service.yaml new file mode 100644 index 0000000000..858c83a4c3 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/service.yaml @@ -0,0 +1,72 @@ +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if .Values.alertmanager.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager + self-monitor: {{ .Values.alertmanager.serviceMonitor.selfMonitor | quote }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.alertmanager.service.labels }} +{{ toYaml .Values.alertmanager.service.labels | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.service.annotations }} + annotations: +{{ toYaml .Values.alertmanager.service.annotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.alertmanager.service.clusterIP }} + clusterIP: {{ .Values.alertmanager.service.clusterIP }} +{{- end }} +{{- if .Values.alertmanager.service.externalIPs }} + externalIPs: +{{ toYaml .Values.alertmanager.service.externalIPs | indent 4 }} +{{- end }} +{{- if .Values.alertmanager.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.alertmanager.service.loadBalancerIP }} +{{- end }} +{{- if .Values.alertmanager.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.alertmanager.service.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} +{{- end }} +{{- if ne .Values.alertmanager.service.type "ClusterIP" }} + externalTrafficPolicy: {{ .Values.alertmanager.service.externalTrafficPolicy }} +{{- end }} + ports: + - name: {{ .Values.alertmanager.alertmanagerSpec.portName }} + {{- if eq .Values.alertmanager.service.type "NodePort" }} + nodePort: {{ .Values.alertmanager.service.nodePort }} + {{- end }} + port: {{ .Values.alertmanager.service.port }} + targetPort: {{ .Values.alertmanager.service.targetPort }} + protocol: TCP + - name: reloader-web + {{- if semverCompare ">=1.20.0-0" $kubeTargetVersion }} + appProtocol: http + {{- end }} + port: 8080 + targetPort: reloader-web +{{- if .Values.alertmanager.service.additionalPorts }} +{{ toYaml .Values.alertmanager.service.additionalPorts | indent 2 }} +{{- end }} + selector: + app.kubernetes.io/name: alertmanager + alertmanager: {{ template "kube-prometheus-stack.alertmanager.crname" . }} +{{- if .Values.alertmanager.service.sessionAffinity }} + sessionAffinity: {{ .Values.alertmanager.service.sessionAffinity }} +{{- end }} +{{- if eq .Values.alertmanager.service.sessionAffinity "ClientIP" }} + sessionAffinityConfig: + clientIP: + timeoutSeconds: {{ .Values.alertmanager.service.sessionAffinityConfig.clientIP.timeoutSeconds }} +{{- end }} + type: "{{ .Values.alertmanager.service.type }}" +{{- if .Values.alertmanager.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.alertmanager.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.alertmanager.service.ipDualStack.ipFamilyPolicy }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/serviceaccount.yaml new file mode 100644 index 0000000000..745ced8bde --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/serviceaccount.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.alertmanager.enabled .Values.alertmanager.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kube-prometheus-stack.alertmanager.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager + app.kubernetes.io/name: {{ template "kube-prometheus-stack.name" . }}-alertmanager + app.kubernetes.io/component: alertmanager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.alertmanager.serviceAccount.annotations }} + annotations: +{{ toYaml .Values.alertmanager.serviceAccount.annotations | indent 4 }} +{{- end }} +automountServiceAccountToken: {{ .Values.alertmanager.serviceAccount.automountServiceAccountToken }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2}} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/servicemonitor.yaml new file mode 100644 index 0000000000..ffba880ae1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/servicemonitor.yaml @@ -0,0 +1,84 @@ +{{- if and .Values.alertmanager.enabled .Values.alertmanager.serviceMonitor.selfMonitor }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- with .Values.alertmanager.serviceMonitor.additionalLabels }} +{{- toYaml . | nindent 4 }} +{{- end }} +spec: + {{- include "servicemonitor.scrapeLimits" .Values.alertmanager.serviceMonitor | nindent 2 }} + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-alertmanager + release: {{ $.Release.Name | quote }} + self-monitor: "true" + namespaceSelector: + matchNames: + - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }} + endpoints: + - port: {{ .Values.alertmanager.alertmanagerSpec.portName }} + enableHttp2: {{ .Values.alertmanager.serviceMonitor.enableHttp2 }} + {{- if .Values.alertmanager.serviceMonitor.interval }} + interval: {{ .Values.alertmanager.serviceMonitor.interval }} + {{- end }} + {{- if .Values.alertmanager.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.alertmanager.serviceMonitor.proxyUrl}} + {{- end }} + {{- if .Values.alertmanager.serviceMonitor.scheme }} + scheme: {{ .Values.alertmanager.serviceMonitor.scheme }} + {{- end }} + {{- if .Values.alertmanager.serviceMonitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.alertmanager.serviceMonitor.bearerTokenFile }} + {{- end }} + {{- if .Values.alertmanager.serviceMonitor.tlsConfig }} + tlsConfig: {{- toYaml .Values.alertmanager.serviceMonitor.tlsConfig | nindent 6 }} + {{- end }} + path: "{{ trimSuffix "/" .Values.alertmanager.alertmanagerSpec.routePrefix }}/metrics" + metricRelabelings: + {{- if .Values.alertmanager.serviceMonitor.metricRelabelings }} + {{- tpl (toYaml .Values.alertmanager.serviceMonitor.metricRelabelings | nindent 6) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName }} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} + {{- if .Values.alertmanager.serviceMonitor.relabelings }} + relabelings: {{- toYaml .Values.alertmanager.serviceMonitor.relabelings | nindent 6 }} + {{- end }} + {{- range .Values.alertmanager.serviceMonitor.additionalEndpoints }} + - port: {{ .port }} + {{- if or $.Values.alertmanager.serviceMonitor.interval .interval }} + interval: {{ default $.Values.alertmanager.serviceMonitor.interval .interval }} + {{- end }} + {{- if or $.Values.alertmanager.serviceMonitor.proxyUrl .proxyUrl }} + proxyUrl: {{ default $.Values.alertmanager.serviceMonitor.proxyUrl .proxyUrl }} + {{- end }} + {{- if or $.Values.alertmanager.serviceMonitor.scheme .scheme }} + scheme: {{ default $.Values.alertmanager.serviceMonitor.scheme .scheme }} + {{- end }} + {{- if or $.Values.alertmanager.serviceMonitor.bearerTokenFile .bearerTokenFile }} + bearerTokenFile: {{ default $.Values.alertmanager.serviceMonitor.bearerTokenFile .bearerTokenFile }} + {{- end }} + {{- if or $.Values.alertmanager.serviceMonitor.tlsConfig .tlsConfig }} + tlsConfig: {{- default $.Values.alertmanager.serviceMonitor.tlsConfig .tlsConfig | toYaml | nindent 6 }} + {{- end }} + path: {{ .path }} + {{- if or $.Values.alertmanager.serviceMonitor.metricRelabelings .metricRelabelings }} + metricRelabelings: {{- tpl (default $.Values.alertmanager.serviceMonitor.metricRelabelings .metricRelabelings | toYaml | nindent 6) . }} + {{- end }} + {{- if or $.Values.alertmanager.serviceMonitor.relabelings .relabelings }} + relabelings: {{- default $.Values.alertmanager.serviceMonitor.relabelings .relabelings | toYaml | nindent 6 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/serviceperreplica.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/serviceperreplica.yaml new file mode 100644 index 0000000000..75a13bdf97 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/alertmanager/serviceperreplica.yaml @@ -0,0 +1,49 @@ +{{- if and .Values.alertmanager.enabled .Values.alertmanager.servicePerReplica.enabled }} +{{- $count := .Values.alertmanager.alertmanagerSpec.replicas | int -}} +{{- $serviceValues := .Values.alertmanager.servicePerReplica -}} +apiVersion: v1 +kind: List +metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-serviceperreplica + namespace: {{ template "kube-prometheus-stack.namespace" . }} +items: +{{- range $i, $e := until $count }} + - apiVersion: v1 + kind: Service + metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-alertmanager-{{ $i }} + namespace: {{ template "kube-prometheus-stack.namespace" $ }} + labels: + app: {{ include "kube-prometheus-stack.name" $ }}-alertmanager +{{ include "kube-prometheus-stack.labels" $ | indent 8 }} + {{- if $serviceValues.annotations }} + annotations: +{{ toYaml $serviceValues.annotations | indent 8 }} + {{- end }} + spec: + {{- if $serviceValues.clusterIP }} + clusterIP: {{ $serviceValues.clusterIP }} + {{- end }} + {{- if $serviceValues.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := $serviceValues.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} + {{- end }} + {{- if ne $serviceValues.type "ClusterIP" }} + externalTrafficPolicy: {{ $serviceValues.externalTrafficPolicy }} + {{- end }} + ports: + - name: {{ $.Values.alertmanager.alertmanagerSpec.portName }} + {{- if eq $serviceValues.type "NodePort" }} + nodePort: {{ $serviceValues.nodePort }} + {{- end }} + port: {{ $serviceValues.port }} + targetPort: {{ $serviceValues.targetPort }} + selector: + app.kubernetes.io/name: alertmanager + alertmanager: {{ template "kube-prometheus-stack.alertmanager.crname" $ }} + statefulset.kubernetes.io/pod-name: alertmanager-{{ include "kube-prometheus-stack.alertmanager.crname" $ }}-{{ $i }} + type: "{{ $serviceValues.type }}" +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/core-dns/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/core-dns/service.yaml new file mode 100644 index 0000000000..5dedc369df --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/core-dns/service.yaml @@ -0,0 +1,28 @@ +{{- if and .Values.coreDns.enabled .Values.coreDns.service.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-coredns + labels: + app: {{ template "kube-prometheus-stack.name" . }}-coredns + jobLabel: coredns +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +spec: + clusterIP: None + {{- if .Values.coreDns.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.coreDns.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.coreDns.service.ipDualStack.ipFamilyPolicy }} + {{- end }} + ports: + - name: {{ .Values.coreDns.serviceMonitor.port }} + port: {{ .Values.coreDns.service.port }} + protocol: TCP + targetPort: {{ .Values.coreDns.service.targetPort }} + selector: + {{- if .Values.coreDns.service.selector }} +{{ toYaml .Values.coreDns.service.selector | indent 4 }} + {{- else}} + k8s-app: kube-dns + {{- end}} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/core-dns/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/core-dns/servicemonitor.yaml new file mode 100644 index 0000000000..dc15a06937 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/core-dns/servicemonitor.yaml @@ -0,0 +1,58 @@ +{{- if and .Values.coreDns.enabled .Values.coreDns.serviceMonitor.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-coredns + {{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + namespace: kube-system + {{- else }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-coredns + {{- with .Values.coreDns.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + jobLabel: {{ .Values.coreDns.serviceMonitor.jobLabel }} + {{- include "servicemonitor.scrapeLimits" .Values.coreDns.serviceMonitor | nindent 2 }} + selector: + {{- if .Values.coreDns.serviceMonitor.selector }} + {{ tpl (toYaml .Values.coreDns.serviceMonitor.selector | nindent 4) . }} + {{- else }} + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-coredns + release: {{ $.Release.Name | quote }} + {{- end }} + namespaceSelector: + matchNames: + - "kube-system" + endpoints: + - port: {{ .Values.coreDns.serviceMonitor.port }} + {{- if .Values.coreDns.serviceMonitor.interval}} + interval: {{ .Values.coreDns.serviceMonitor.interval }} + {{- end }} + {{- if .Values.coreDns.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.coreDns.serviceMonitor.proxyUrl}} + {{- end }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + metricRelabelings: + {{- if .Values.coreDns.serviceMonitor.metricRelabelings }} + {{ tpl (toYaml .Values.coreDns.serviceMonitor.metricRelabelings | indent 4) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName }} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.coreDns.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.coreDns.serviceMonitor.relabelings | indent 4) . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-api-server/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-api-server/servicemonitor.yaml new file mode 100644 index 0000000000..66e777632e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-api-server/servicemonitor.yaml @@ -0,0 +1,57 @@ +{{- if and .Values.kubeApiServer.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-apiserver + {{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + namespace: default + {{- else }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-apiserver + {{- with .Values.kubeApiServer.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + {{- include "servicemonitor.scrapeLimits" .Values.kubeApiServer.serviceMonitor | nindent 2 }} + endpoints: + - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + {{- if .Values.kubeApiServer.serviceMonitor.interval }} + interval: {{ .Values.kubeApiServer.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubeApiServer.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubeApiServer.serviceMonitor.proxyUrl }} + {{- end }} + port: https + scheme: https + metricRelabelings: + {{- if .Values.kubeApiServer.serviceMonitor.metricRelabelings }} +{{ tpl (toYaml .Values.kubeApiServer.serviceMonitor.metricRelabelings | indent 6) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.kubeApiServer.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.kubeApiServer.serviceMonitor.relabelings | indent 6) . }} +{{- end }} + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + serverName: {{ .Values.kubeApiServer.tlsConfig.serverName }} + insecureSkipVerify: {{ .Values.kubeApiServer.tlsConfig.insecureSkipVerify }} + jobLabel: {{ .Values.kubeApiServer.serviceMonitor.jobLabel }} + namespaceSelector: + matchNames: + - default + selector: +{{ toYaml .Values.kubeApiServer.serviceMonitor.selector | indent 4 }} +{{- end}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/endpoints.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/endpoints.yaml new file mode 100644 index 0000000000..6a6afa6412 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/endpoints.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.kubeControllerManager.enabled .Values.kubeControllerManager.endpoints .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Endpoints +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-controller-manager + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-controller-manager + k8s-app: kube-controller-manager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +subsets: + - addresses: + {{- range .Values.kubeControllerManager.endpoints }} + - ip: {{ . }} + {{- end }} + ports: + - name: {{ .Values.kubeControllerManager.serviceMonitor.port }} + {{- $kubeControllerManagerDefaultInsecurePort := 10252 }} + {{- $kubeControllerManagerDefaultSecurePort := 10257 }} + port: {{ include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . $kubeControllerManagerDefaultInsecurePort $kubeControllerManagerDefaultSecurePort .Values.kubeControllerManager.service.port) }} + protocol: TCP +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/service.yaml new file mode 100644 index 0000000000..0a901c4acf --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/service.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.kubeControllerManager.enabled .Values.kubeControllerManager.service.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-controller-manager + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-controller-manager + jobLabel: kube-controller-manager +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +spec: + clusterIP: None + {{- if .Values.kubeControllerManager.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.kubeControllerManager.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.kubeControllerManager.service.ipDualStack.ipFamilyPolicy }} + {{- end }} + ports: + - name: {{ .Values.kubeControllerManager.serviceMonitor.port }} + {{- $kubeControllerManagerDefaultInsecurePort := 10252 }} + {{- $kubeControllerManagerDefaultSecurePort := 10257 }} + port: {{ include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . $kubeControllerManagerDefaultInsecurePort $kubeControllerManagerDefaultSecurePort .Values.kubeControllerManager.service.port) }} + protocol: TCP + targetPort: {{ include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . $kubeControllerManagerDefaultInsecurePort $kubeControllerManagerDefaultSecurePort .Values.kubeControllerManager.service.targetPort) }} +{{- if .Values.kubeControllerManager.endpoints }}{{- else }} + selector: + {{- if .Values.kubeControllerManager.service.selector }} +{{ toYaml .Values.kubeControllerManager.service.selector | indent 4 }} + {{- else}} + component: kube-controller-manager + {{- end}} +{{- end }} + type: ClusterIP +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/servicemonitor.yaml new file mode 100644 index 0000000000..7ed3baa65f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-controller-manager/servicemonitor.yaml @@ -0,0 +1,69 @@ +{{- if and .Values.kubeControllerManager.enabled .Values.kubeControllerManager.serviceMonitor.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-controller-manager + {{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + namespace: kube-system + {{- else }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-controller-manager + {{- with .Values.kubeControllerManager.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + jobLabel: {{ .Values.kubeControllerManager.serviceMonitor.jobLabel }} + {{- include "servicemonitor.scrapeLimits" .Values.kubeControllerManager.serviceMonitor | nindent 2 }} + selector: + {{- if .Values.kubeControllerManager.serviceMonitor.selector }} + {{ tpl (toYaml .Values.kubeControllerManager.serviceMonitor.selector | nindent 4) . }} + {{- else }} + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-controller-manager + release: {{ $.Release.Name | quote }} + {{- end }} + namespaceSelector: + matchNames: + - "kube-system" + endpoints: + - port: {{ .Values.kubeControllerManager.serviceMonitor.port }} + {{- if .Values.kubeControllerManager.serviceMonitor.interval }} + interval: {{ .Values.kubeControllerManager.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + {{- if .Values.kubeControllerManager.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubeControllerManager.serviceMonitor.proxyUrl}} + {{- end }} + {{- if eq (include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . false true .Values.kubeControllerManager.serviceMonitor.https )) "true" }} + scheme: https + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + {{- if eq (include "kube-prometheus-stack.kubeControllerManager.insecureScrape" (list . nil true .Values.kubeControllerManager.serviceMonitor.insecureSkipVerify)) "true" }} + insecureSkipVerify: true + {{- end }} + {{- if .Values.kubeControllerManager.serviceMonitor.serverName }} + serverName: {{ .Values.kubeControllerManager.serviceMonitor.serverName }} + {{- end }} + {{- end }} + metricRelabelings: + {{- if.Values.kubeControllerManager.serviceMonitor.metricRelabelings }} + {{ tpl (toYaml .Values.kubeControllerManager.serviceMonitor.metricRelabelings | indent 4) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.kubeControllerManager.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.kubeControllerManager.serviceMonitor.relabelings | indent 4) . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-dns/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-dns/service.yaml new file mode 100644 index 0000000000..478f419400 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-dns/service.yaml @@ -0,0 +1,32 @@ +{{- if and .Values.kubeDns.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-dns + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-dns + jobLabel: kube-dns +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +spec: + clusterIP: None + {{- if .Values.kubeDns.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.kubeDns.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.kubeDns.service.ipDualStack.ipFamilyPolicy }} + {{- end }} + ports: + - name: http-metrics-dnsmasq + port: {{ .Values.kubeDns.service.dnsmasq.port }} + protocol: TCP + targetPort: {{ .Values.kubeDns.service.dnsmasq.targetPort }} + - name: http-metrics-skydns + port: {{ .Values.kubeDns.service.skydns.port }} + protocol: TCP + targetPort: {{ .Values.kubeDns.service.skydns.targetPort }} + selector: + {{- if .Values.kubeDns.service.selector }} +{{ toYaml .Values.kubeDns.service.selector | indent 4 }} + {{- else}} + k8s-app: kube-dns + {{- end}} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-dns/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-dns/servicemonitor.yaml new file mode 100644 index 0000000000..9fa41b575f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-dns/servicemonitor.yaml @@ -0,0 +1,71 @@ +{{- if and .Values.kubeDns.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-dns + {{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + namespace: kube-system + {{- else }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-dns + {{- with .Values.kubeDns.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + jobLabel: {{ .Values.kubeDns.serviceMonitor.jobLabel }} + {{- include "servicemonitor.scrapeLimits" .Values.kubeDns.serviceMonitor | nindent 2 }} + selector: + {{- if .Values.kubeDns.serviceMonitor.selector }} + {{ tpl (toYaml .Values.kubeDns.serviceMonitor.selector | nindent 4) . }} + {{- else }} + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-dns + release: {{ $.Release.Name | quote }} + {{- end }} + namespaceSelector: + matchNames: + - "kube-system" + endpoints: + - port: http-metrics-dnsmasq + {{- if .Values.kubeDns.serviceMonitor.interval }} + interval: {{ .Values.kubeDns.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + {{- if .Values.kubeDns.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubeDns.serviceMonitor.proxyUrl}} + {{- end }} + metricRelabelings: + {{- if .Values.kubeDns.serviceMonitor.dnsmasqMetricRelabelings }} + {{ tpl (toYaml .Values.kubeDns.serviceMonitor.dnsmasqMetricRelabelings | indent 4) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.kubeDns.serviceMonitor.dnsmasqRelabelings }} + relabelings: +{{ toYaml .Values.kubeDns.serviceMonitor.dnsmasqRelabelings | indent 4 }} +{{- end }} + - port: http-metrics-skydns + {{- if .Values.kubeDns.serviceMonitor.interval }} + interval: {{ .Values.kubeDns.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +{{- if .Values.kubeDns.serviceMonitor.metricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.kubeDns.serviceMonitor.metricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubeDns.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.kubeDns.serviceMonitor.relabelings | indent 4) . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/endpoints.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/endpoints.yaml new file mode 100644 index 0000000000..e366447577 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/endpoints.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.kubeEtcd.enabled .Values.kubeEtcd.endpoints .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Endpoints +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-etcd + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-etcd + k8s-app: etcd-server +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +subsets: + - addresses: + {{- range .Values.kubeEtcd.endpoints }} + - ip: {{ . }} + {{- end }} + ports: + - name: {{ .Values.kubeEtcd.serviceMonitor.port }} + port: {{ .Values.kubeEtcd.service.port }} + protocol: TCP +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/service.yaml new file mode 100644 index 0000000000..a62059aa4e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/service.yaml @@ -0,0 +1,31 @@ +{{- if and .Values.kubeEtcd.enabled .Values.kubeEtcd.service.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-etcd + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-etcd + jobLabel: kube-etcd +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +spec: + clusterIP: None + {{- if .Values.kubeEtcd.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.kubeEtcd.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.kubeEtcd.service.ipDualStack.ipFamilyPolicy }} + {{- end }} + ports: + - name: {{ .Values.kubeEtcd.serviceMonitor.port }} + port: {{ .Values.kubeEtcd.service.port }} + protocol: TCP + targetPort: {{ .Values.kubeEtcd.service.targetPort }} +{{- if .Values.kubeEtcd.endpoints }}{{- else }} + selector: + {{- if .Values.kubeEtcd.service.selector }} +{{ toYaml .Values.kubeEtcd.service.selector | indent 4 }} + {{- else}} + component: etcd + {{- end}} +{{- end }} + type: ClusterIP +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/servicemonitor.yaml new file mode 100644 index 0000000000..26fdbdbed3 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-etcd/servicemonitor.yaml @@ -0,0 +1,75 @@ +{{- if and .Values.kubeEtcd.enabled .Values.kubeEtcd.serviceMonitor.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-etcd + {{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + namespace: kube-system + {{- else }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-etcd + {{- with .Values.kubeEtcd.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + jobLabel: {{ .Values.kubeEtcd.serviceMonitor.jobLabel }} + {{- include "servicemonitor.scrapeLimits" .Values.kubeEtcd.serviceMonitor | nindent 4 }} + selector: + {{- if .Values.kubeEtcd.serviceMonitor.selector }} + {{ tpl (toYaml .Values.kubeEtcd.serviceMonitor.selector | nindent 4) . }} + {{- else }} + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-etcd + release: {{ $.Release.Name | quote }} + {{- end }} + namespaceSelector: + matchNames: + - "kube-system" + endpoints: + - port: {{ .Values.kubeEtcd.serviceMonitor.port }} + {{- if .Values.kubeEtcd.serviceMonitor.interval }} + interval: {{ .Values.kubeEtcd.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + {{- if .Values.kubeEtcd.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubeEtcd.serviceMonitor.proxyUrl}} + {{- end }} + {{- if eq .Values.kubeEtcd.serviceMonitor.scheme "https" }} + scheme: https + tlsConfig: + {{- if .Values.kubeEtcd.serviceMonitor.serverName }} + serverName: {{ .Values.kubeEtcd.serviceMonitor.serverName }} + {{- end }} + {{- if .Values.kubeEtcd.serviceMonitor.caFile }} + caFile: {{ .Values.kubeEtcd.serviceMonitor.caFile }} + {{- end }} + {{- if .Values.kubeEtcd.serviceMonitor.certFile }} + certFile: {{ .Values.kubeEtcd.serviceMonitor.certFile }} + {{- end }} + {{- if .Values.kubeEtcd.serviceMonitor.keyFile }} + keyFile: {{ .Values.kubeEtcd.serviceMonitor.keyFile }} + {{- end}} + insecureSkipVerify: {{ .Values.kubeEtcd.serviceMonitor.insecureSkipVerify }} + {{- end }} + metricRelabelings: + {{- if .Values.kubeEtcd.serviceMonitor.metricRelabelings }} + {{ tpl (toYaml .Values.kubeEtcd.serviceMonitor.metricRelabelings | indent 4) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.kubeEtcd.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.kubeEtcd.serviceMonitor.relabelings | indent 4) . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/endpoints.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/endpoints.yaml new file mode 100644 index 0000000000..8613e62425 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/endpoints.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.kubeProxy.enabled .Values.kubeProxy.endpoints .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Endpoints +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-proxy + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-proxy + k8s-app: kube-proxy +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +subsets: + - addresses: + {{- range .Values.kubeProxy.endpoints }} + - ip: {{ . }} + {{- end }} + ports: + - name: {{ .Values.kubeProxy.serviceMonitor.port }} + port: {{ .Values.kubeProxy.service.port }} + protocol: TCP +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/service.yaml new file mode 100644 index 0000000000..672f5492b8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/service.yaml @@ -0,0 +1,31 @@ +{{- if and .Values.kubeProxy.enabled .Values.kubeProxy.service.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-proxy + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-proxy + jobLabel: kube-proxy +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +spec: + clusterIP: None + {{- if .Values.kubeProxy.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.kubeProxy.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.kubeProxy.service.ipDualStack.ipFamilyPolicy }} + {{- end }} + ports: + - name: {{ .Values.kubeProxy.serviceMonitor.port }} + port: {{ .Values.kubeProxy.service.port }} + protocol: TCP + targetPort: {{ .Values.kubeProxy.service.targetPort }} +{{- if .Values.kubeProxy.endpoints }}{{- else }} + selector: + {{- if .Values.kubeProxy.service.selector }} +{{ toYaml .Values.kubeProxy.service.selector | indent 4 }} + {{- else}} + k8s-app: kube-proxy + {{- end}} +{{- end }} + type: ClusterIP +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/servicemonitor.yaml new file mode 100644 index 0000000000..24b0ab2001 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-proxy/servicemonitor.yaml @@ -0,0 +1,63 @@ +{{- if and .Values.kubeProxy.enabled .Values.kubeProxy.serviceMonitor.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-proxy + {{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + namespace: kube-system + {{- else }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-proxy + {{- with .Values.kubeProxy.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + jobLabel: {{ .Values.kubeProxy.serviceMonitor.jobLabel }} + {{- include "servicemonitor.scrapeLimits" .Values.kubeProxy.serviceMonitor | nindent 2 }} + selector: + {{- if .Values.kubeProxy.serviceMonitor.selector }} + {{ tpl (toYaml .Values.kubeProxy.serviceMonitor.selector | nindent 4) . }} + {{- else }} + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-proxy + release: {{ $.Release.Name | quote }} + {{- end }} + namespaceSelector: + matchNames: + - "kube-system" + endpoints: + - port: {{ .Values.kubeProxy.serviceMonitor.port }} + {{- if .Values.kubeProxy.serviceMonitor.interval }} + interval: {{ .Values.kubeProxy.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + {{- if .Values.kubeProxy.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubeProxy.serviceMonitor.proxyUrl}} + {{- end }} + {{- if .Values.kubeProxy.serviceMonitor.https }} + scheme: https + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + {{- end}} + metricRelabelings: + {{- if .Values.kubeProxy.serviceMonitor.metricRelabelings }} + {{ tpl (toYaml .Values.kubeProxy.serviceMonitor.metricRelabelings | indent 4) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.kubeProxy.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.kubeProxy.serviceMonitor.relabelings | indent 4) . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/endpoints.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/endpoints.yaml new file mode 100644 index 0000000000..6236b42f10 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/endpoints.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.kubeScheduler.enabled .Values.kubeScheduler.endpoints .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Endpoints +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-scheduler + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-scheduler + k8s-app: kube-scheduler +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +subsets: + - addresses: + {{- range .Values.kubeScheduler.endpoints }} + - ip: {{ . }} + {{- end }} + ports: + - name: {{ .Values.kubeScheduler.serviceMonitor.port }} + {{- $kubeSchedulerDefaultInsecurePort := 10251 }} + {{- $kubeSchedulerDefaultSecurePort := 10259 }} + port: {{ include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . $kubeSchedulerDefaultInsecurePort $kubeSchedulerDefaultSecurePort .Values.kubeScheduler.service.port) }} + protocol: TCP +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/service.yaml new file mode 100644 index 0000000000..8663d79f0d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/service.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.kubeScheduler.enabled .Values.kubeScheduler.service.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-scheduler + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-scheduler + jobLabel: kube-scheduler +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: kube-system +spec: + clusterIP: None + {{- if .Values.kubeScheduler.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.kubeScheduler.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.kubeScheduler.service.ipDualStack.ipFamilyPolicy }} + {{- end }} + ports: + - name: {{ .Values.kubeScheduler.serviceMonitor.port }} + {{- $kubeSchedulerDefaultInsecurePort := 10251 }} + {{- $kubeSchedulerDefaultSecurePort := 10259 }} + port: {{ include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . $kubeSchedulerDefaultInsecurePort $kubeSchedulerDefaultSecurePort .Values.kubeScheduler.service.port) }} + protocol: TCP + targetPort: {{ include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . $kubeSchedulerDefaultInsecurePort $kubeSchedulerDefaultSecurePort .Values.kubeScheduler.service.targetPort) }} +{{- if .Values.kubeScheduler.endpoints }}{{- else }} + selector: + {{- if .Values.kubeScheduler.service.selector }} +{{ toYaml .Values.kubeScheduler.service.selector | indent 4 }} + {{- else}} + component: kube-scheduler + {{- end}} +{{- end }} + type: ClusterIP +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/servicemonitor.yaml new file mode 100644 index 0000000000..b17c4f1d47 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-scheduler/servicemonitor.yaml @@ -0,0 +1,69 @@ +{{- if and .Values.kubeScheduler.enabled .Values.kubeScheduler.serviceMonitor.enabled .Values.kubernetesServiceMonitors.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kube-scheduler + {{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + namespace: kube-system + {{- else }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-scheduler + {{- with .Values.kubeScheduler.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + jobLabel: {{ .Values.kubeScheduler.serviceMonitor.jobLabel }} + {{- include "servicemonitor.scrapeLimits" .Values.kubeScheduler.serviceMonitor | nindent 2 }} + selector: + {{- if .Values.kubeScheduler.serviceMonitor.selector }} + {{ tpl (toYaml .Values.kubeScheduler.serviceMonitor.selector | nindent 4) . }} + {{- else }} + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-kube-scheduler + release: {{ $.Release.Name | quote }} + {{- end }} + namespaceSelector: + matchNames: + - "kube-system" + endpoints: + - port: {{ .Values.kubeScheduler.serviceMonitor.port }} + {{- if .Values.kubeScheduler.serviceMonitor.interval }} + interval: {{ .Values.kubeScheduler.serviceMonitor.interval }} + {{- end }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + {{- if .Values.kubeScheduler.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubeScheduler.serviceMonitor.proxyUrl}} + {{- end }} + {{- if eq (include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . false true .Values.kubeScheduler.serviceMonitor.https )) "true" }} + scheme: https + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + {{- if eq (include "kube-prometheus-stack.kubeScheduler.insecureScrape" (list . nil true .Values.kubeScheduler.serviceMonitor.insecureSkipVerify)) "true" }} + insecureSkipVerify: true + {{- end }} + {{- if .Values.kubeScheduler.serviceMonitor.serverName }} + serverName: {{ .Values.kubeScheduler.serviceMonitor.serverName }} + {{- end}} + {{- end}} + metricRelabelings: + {{- if .Values.kubeScheduler.serviceMonitor.metricRelabelings }} + {{ tpl (toYaml .Values.kubeScheduler.serviceMonitor.metricRelabelings | indent 4) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.kubeScheduler.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.kubeScheduler.serviceMonitor.relabelings | indent 4) . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-state-metrics/validate.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-state-metrics/validate.yaml new file mode 100644 index 0000000000..9211b3d771 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kube-state-metrics/validate.yaml @@ -0,0 +1,7 @@ +{{- if .Values.kubeStateMetrics.enabled }} +{{- if not (kindIs "invalid" .Values.kubeStateMetrics.serviceMonitor) }} +{{- if .Values.kubeStateMetrics.serviceMonitor.namespaceOverride }} +{{- fail "kubeStateMetrics.serviceMonitor.namespaceOverride was removed. Please use kube-state-metrics.namespaceOverride instead." }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kubelet/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kubelet/servicemonitor.yaml new file mode 100644 index 0000000000..f570fbfdbc --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/kubelet/servicemonitor.yaml @@ -0,0 +1,246 @@ +{{- if (and (not .Values.kubelet.enabled) .Values.hardenedKubelet.enabled) }} +{{ required "Cannot set .Values.hardenedKubelet.enabled=true when .Values.kubelet.enabled=false" "" }} +{{- end }} +{{- if (and .Values.kubelet.enabled .Values.kubernetesServiceMonitors.enabled (not .Values.hardenedKubelet.enabled) (not .Values.k3sServer.enabled)) }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-kubelet + {{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + namespace: {{ .Values.kubelet.namespace }} + {{- else }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-kubelet + {{- with .Values.kubelet.serviceMonitor.additionalLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +{{- include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + {{- include "servicemonitor.scrapeLimits" .Values.kubelet.serviceMonitor | nindent 2 }} + {{- with .Values.kubelet.serviceMonitor.attachMetadata }} + attachMetadata: + {{- toYaml . | nindent 4 }} + {{- end }} + endpoints: + {{- if .Values.kubelet.serviceMonitor.https }} + - port: https-metrics + scheme: https + {{- if .Values.kubelet.serviceMonitor.interval }} + interval: {{ .Values.kubelet.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }} + {{- end }} + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecureSkipVerify: true + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + honorLabels: {{ .Values.kubelet.serviceMonitor.honorLabels }} + honorTimestamps: {{ .Values.kubelet.serviceMonitor.honorTimestamps }} + metricRelabelings: + {{- if .Values.kubelet.serviceMonitor.metricRelabelings }} + {{- tpl (toYaml .Values.kubelet.serviceMonitor.metricRelabelings | nindent 6) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.kubelet.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.relabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.cAdvisor }} + - port: https-metrics + scheme: https + path: /metrics/cadvisor + {{- if .Values.kubelet.serviceMonitor.interval }} + interval: {{ .Values.kubelet.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }} + {{- end }} + honorLabels: {{ .Values.kubelet.serviceMonitor.honorLabels }} + honorTimestamps: {{ .Values.kubelet.serviceMonitor.honorTimestamps }} + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecureSkipVerify: true + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +{{- if .Values.kubelet.serviceMonitor.cAdvisorMetricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.cAdvisorMetricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.cAdvisorRelabelings }} + relabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.cAdvisorRelabelings | indent 4) . }} +{{- end }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.probes }} + - port: https-metrics + scheme: https + path: /metrics/probes + {{- if .Values.kubelet.serviceMonitor.interval }} + interval: {{ .Values.kubelet.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }} + {{- end }} + honorLabels: {{ .Values.kubelet.serviceMonitor.honorLabels }} + honorTimestamps: {{ .Values.kubelet.serviceMonitor.honorTimestamps }} + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecureSkipVerify: true + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +{{- if .Values.kubelet.serviceMonitor.probesMetricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.probesMetricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.probesRelabelings }} + relabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.probesRelabelings | indent 4) . }} +{{- end }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.resource }} + - port: https-metrics + scheme: https + path: {{ include "kubelet.serviceMonitor.resourcePath" . }} + {{- if .Values.kubelet.serviceMonitor.interval }} + interval: {{ .Values.kubelet.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }} + {{- end }} + honorLabels: {{ .Values.kubelet.serviceMonitor.honorLabels }} + honorTimestamps: {{ .Values.kubelet.serviceMonitor.honorTimestamps }} + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecureSkipVerify: true + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +{{- if .Values.kubelet.serviceMonitor.resourceMetricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.resourceMetricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.resourceRelabelings }} + relabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.resourceRelabelings | indent 4) . }} +{{- end }} +{{- end }} + {{- else }} + - port: http-metrics + {{- if .Values.kubelet.serviceMonitor.interval }} + interval: {{ .Values.kubelet.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }} + {{- end }} + honorLabels: {{ .Values.kubelet.serviceMonitor.honorLabels }} + honorTimestamps: {{ .Values.kubelet.serviceMonitor.honorTimestamps }} +{{- if .Values.kubelet.serviceMonitor.metricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.metricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.relabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.cAdvisor }} + - port: http-metrics + path: /metrics/cadvisor + {{- if .Values.kubelet.serviceMonitor.interval }} + interval: {{ .Values.kubelet.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }} + {{- end }} + honorLabels: {{ .Values.kubelet.serviceMonitor.honorLabels }} + honorTimestamps: {{ .Values.kubelet.serviceMonitor.honorTimestamps }} +{{- if .Values.kubelet.serviceMonitor.cAdvisorMetricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.cAdvisorMetricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.cAdvisorRelabelings }} + relabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.cAdvisorRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.probes }} + - port: http-metrics + path: /metrics/probes + {{- if .Values.kubelet.serviceMonitor.interval }} + interval: {{ .Values.kubelet.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }} + {{- end }} + honorLabels: {{ .Values.kubelet.serviceMonitor.honorLabels }} + honorTimestamps: {{ .Values.kubelet.serviceMonitor.honorTimestamps }} +{{- if .Values.kubelet.serviceMonitor.probesMetricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.probesMetricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.probesRelabelings }} + relabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.probesRelabelings | indent 4) . }} +{{- end }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.resource }} + - port: http-metrics + path: {{ include "kubelet.serviceMonitor.resourcePath" . }} + {{- if .Values.kubelet.serviceMonitor.interval }} + interval: {{ .Values.kubelet.serviceMonitor.interval }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.kubelet.serviceMonitor.proxyUrl }} + {{- end }} + {{- if .Values.kubelet.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.kubelet.serviceMonitor.scrapeTimeout }} + {{- end }} + honorLabels: {{ .Values.kubelet.serviceMonitor.honorLabels }} + honorTimestamps: {{ .Values.kubelet.serviceMonitor.honorTimestamps }} +{{- if .Values.kubelet.serviceMonitor.resourceMetricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.resourceMetricRelabelings | indent 4) . }} +{{- end }} +{{- if .Values.kubelet.serviceMonitor.resourceRelabelings }} + relabelings: +{{ tpl (toYaml .Values.kubelet.serviceMonitor.resourceRelabelings | indent 4) . }} +{{- end }} +{{- end }} +{{- end }} + {{- end }} + jobLabel: k8s-app + namespaceSelector: + matchNames: + - {{ .Values.kubelet.namespace }} + selector: + matchLabels: + app.kubernetes.io/name: kubelet + k8s-app: kubelet +{{- end}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/node-exporter/validate.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/node-exporter/validate.yaml new file mode 100644 index 0000000000..bdc73d6165 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/exporters/node-exporter/validate.yaml @@ -0,0 +1,3 @@ +{{- if (and (not .Values.nodeExporter.enabled) .Values.hardenedNodeExporter.enabled) }} +{{ required "Cannot set .Values.hardenedNodeExporter.enabled=true when .Values.nodeExporter.enabled=false" "" }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/extra-objects.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/extra-objects.yaml new file mode 100644 index 0000000000..567f7bf329 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/extra-objects.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraManifests }} +--- +{{ tpl (toYaml .) $ }} +{{ end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/configmap-dashboards.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/configmap-dashboards.yaml new file mode 100644 index 0000000000..e719009ffe --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/configmap-dashboards.yaml @@ -0,0 +1,24 @@ +{{- if or (and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled) .Values.grafana.forceDeployDashboards }} +{{- $files := .Files.Glob "dashboards-1.14/*.json" }} +{{- if $files }} +apiVersion: v1 +kind: ConfigMapList +items: +{{- range $path, $fileContents := $files }} +{{- $dashboardName := regexReplaceAll "(^.*/)(.*)\\.json$" $path "${2}" }} +- apiVersion: v1 + kind: ConfigMap + metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) $dashboardName | trunc 63 | trimSuffix "-" }} + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 6 }} + data: + {{ $dashboardName }}.json: {{ $.Files.Get $path | toJson }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/configmaps-datasources.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/configmaps-datasources.yaml new file mode 100644 index 0000000000..135bad440d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/configmaps-datasources.yaml @@ -0,0 +1,81 @@ +{{- if or (and .Values.grafana.enabled .Values.grafana.sidecar.datasources.enabled) .Values.grafana.forceDeployDatasources }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-grafana-datasource + namespace: {{ default .Values.grafana.sidecar.datasources.searchNamespace (include "kube-prometheus-stack.namespace" .) }} +{{- if .Values.grafana.sidecar.datasources.annotations }} + annotations: + {{- toYaml .Values.grafana.sidecar.datasources.annotations | nindent 4 }} +{{- end }} + labels: + {{ $.Values.grafana.sidecar.datasources.label }}: {{ $.Values.grafana.sidecar.datasources.labelValue | quote }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + datasource.yaml: |- + apiVersion: 1 +{{- if .Values.grafana.deleteDatasources }} + deleteDatasources: +{{ tpl (toYaml .Values.grafana.deleteDatasources | indent 6) . }} +{{- end }} + datasources: +{{- $scrapeInterval := .Values.grafana.sidecar.datasources.defaultDatasourceScrapeInterval | default .Values.prometheus.prometheusSpec.scrapeInterval | default "30s" }} +{{- if .Values.grafana.sidecar.datasources.defaultDatasourceEnabled }} + - name: "{{ .Values.grafana.sidecar.datasources.name }}" + type: prometheus + uid: {{ .Values.grafana.sidecar.datasources.uid }} + {{- if .Values.grafana.sidecar.datasources.url }} + url: {{ .Values.grafana.sidecar.datasources.url }} + {{- else }} + url: http://{{ template "kube-prometheus-stack.fullname" . }}-prometheus.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.prometheus.service.port }}/{{ trimPrefix "/" .Values.prometheus.prometheusSpec.routePrefix }} + {{- end }} + access: proxy + isDefault: {{ .Values.grafana.sidecar.datasources.isDefaultDatasource }} + jsonData: + httpMethod: {{ .Values.grafana.sidecar.datasources.httpMethod }} + timeInterval: {{ $scrapeInterval }} + {{- if .Values.grafana.sidecar.datasources.timeout }} + timeout: {{ .Values.grafana.sidecar.datasources.timeout }} + {{- end }} +{{- if .Values.grafana.sidecar.datasources.exemplarTraceIdDestinations }} + exemplarTraceIdDestinations: + - datasourceUid: {{ .Values.grafana.sidecar.datasources.exemplarTraceIdDestinations.datasourceUid }} + name: {{ .Values.grafana.sidecar.datasources.exemplarTraceIdDestinations.traceIdLabelName }} +{{- end }} +{{- if .Values.grafana.sidecar.datasources.createPrometheusReplicasDatasources }} +{{- range until (int .Values.prometheus.prometheusSpec.replicas) }} + - name: "{{ $.Values.grafana.sidecar.datasources.name }}-{{ . }}" + type: prometheus + uid: {{ $.Values.grafana.sidecar.datasources.uid }}-replica-{{ . }} + url: http://prometheus-{{ template "kube-prometheus-stack.prometheus.crname" $ }}-{{ . }}.prometheus-operated:9090/{{ trimPrefix "/" $.Values.prometheus.prometheusSpec.routePrefix }} + access: proxy + isDefault: false + jsonData: + timeInterval: {{ $scrapeInterval }} +{{- if $.Values.grafana.sidecar.datasources.exemplarTraceIdDestinations }} + exemplarTraceIdDestinations: + - datasourceUid: {{ $.Values.grafana.sidecar.datasources.exemplarTraceIdDestinations.datasourceUid }} + name: {{ $.Values.grafana.sidecar.datasources.exemplarTraceIdDestinations.traceIdLabelName }} +{{- end }} +{{- end }} +{{- end }} +{{- if .Values.grafana.sidecar.datasources.alertmanager.enabled }} + - name: "{{ .Values.grafana.sidecar.datasources.alertmanager.name }}" + type: alertmanager + uid: {{ .Values.grafana.sidecar.datasources.alertmanager.uid }} + {{- if .Values.grafana.sidecar.datasources.alertmanager.url }} + url: {{ .Values.grafana.sidecar.datasources.alertmanager.url }} + {{- else }} + url: http://{{ template "kube-prometheus-stack.fullname" . }}-alertmanager.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.alertmanager.service.port }}/{{ trimPrefix "/" .Values.alertmanager.alertmanagerSpec.routePrefix }} + {{- end }} + access: proxy + jsonData: + handleGrafanaManagedAlerts: {{ .Values.grafana.sidecar.datasources.alertmanager.handleGrafanaManagedAlerts }} + implementation: {{ .Values.grafana.sidecar.datasources.alertmanager.implementation }} +{{- end }} +{{- end }} +{{- if .Values.grafana.additionalDataSources }} +{{ tpl (toYaml .Values.grafana.additionalDataSources | indent 4) . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/alertmanager-overview.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/alertmanager-overview.yaml new file mode 100644 index 0000000000..216467bdf7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/alertmanager-overview.yaml @@ -0,0 +1,616 @@ +{{- /* +Generated from 'alertmanager-overview' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +{{- if and .Values.alertmanager.enabled .Values.alertmanager.serviceMonitor.selfMonitor }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "alertmanager-overview" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + alertmanager-overview.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "30s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "current set of alerts stored in the Alertmanager", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(alertmanager_alerts{namespace=~\"$namespace\",service=~\"$service\"}) by (namespace,service,instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Alerts", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "rate of successful and invalid alerts received by the Alertmanager", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(alertmanager_alerts_received_total{namespace=~\"$namespace\",service=~\"$service\"}[$__rate_interval])) by (namespace,service,instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Received", + "refId": "A" + }, + { + "expr": "sum(rate(alertmanager_alerts_invalid_total{namespace=~\"$namespace\",service=~\"$service\"}[$__rate_interval])) by (namespace,service,instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Invalid", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Alerts receive rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Alerts", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "rate of successful and invalid notifications sent by the Alertmanager", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": "integration", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(alertmanager_notifications_total{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (integration,namespace,service,instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Total", + "refId": "A" + }, + { + "expr": "sum(rate(alertmanager_notifications_failed_total{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (integration,namespace,service,instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Failed", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "$integration: Notifications Send Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "latency of notifications sent by the Alertmanager", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 5, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": "integration", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99,\n sum(rate(alertmanager_notification_latency_seconds_bucket{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (le,namespace,service,instance)\n) \n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} 99th Percentile", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.50,\n sum(rate(alertmanager_notification_latency_seconds_bucket{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (le,namespace,service,instance)\n) \n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Median", + "refId": "B" + }, + { + "expr": "sum(rate(alertmanager_notification_latency_seconds_sum{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (namespace,service,instance)\n/\nsum(rate(alertmanager_notification_latency_seconds_count{namespace=~\"$namespace\",service=~\"$service\", integration=\"$integration\"}[$__rate_interval])) by (namespace,service,instance)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Average", + "refId": "C" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "$integration: Notification Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Notifications", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "alertmanager-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": "namespace", + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(alertmanager_alerts, namespace)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": "service", + "multi": false, + "name": "service", + "options": [ + + ], + "query": "label_values(alertmanager_alerts, service)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "all", + "value": "$__all" + }, + "datasource": "$datasource", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "integration", + "options": [ + + ], + "query": "label_values(alertmanager_notifications_total{integration=~\".*\"}, integration)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Alertmanager / Overview", + "uid": "alertmanager-overview", + "version": 0 + } +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/apiserver.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/apiserver.yaml new file mode 100644 index 0000000000..c05d6ceebb --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/apiserver.yaml @@ -0,0 +1,1772 @@ +{{- /* +Generated from 'apiserver' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.kubeApiServer.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "apiserver" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + apiserver.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "panels": [ + { + "content": "The SLO (service level objective) and other metrics displayed on this dashboard are for informational purposes only.", + "datasource": null, + "description": "The SLO (service level objective) and other metrics displayed on this dashboard are for informational purposes only.", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "mode": "markdown", + "span": 12, + "title": "Notice", + "type": "text" + } + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "decimals": 3, + "description": "How many percent of requests (both read and write) in 30 days have been answered successfully and fast enough?", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + + }, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "rightSide": true + }, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 4, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "apiserver_request:availability30d{verb=\"all\", cluster=\"$cluster\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Availability (30d) > 99.000%", + "tooltip": { + "shared": false + }, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 3, + "description": "How much error budget is left looking at our 0.990% availability guarantees?", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 8, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "100 * (apiserver_request:availability30d{verb=\"all\", cluster=\"$cluster\"} - 0.990000)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "errorbudget", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "ErrorBudget (30d) > 99.000%", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "decimals": 3, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": 3, + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "decimals": 3, + "description": "How many percent of read requests (LIST,GET) in 30 days have been answered successfully and fast enough?", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + + }, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "rightSide": true + }, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "apiserver_request:availability30d{verb=\"read\", cluster=\"$cluster\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Read Availability (30d)", + "tooltip": { + "shared": false + }, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "How many read requests (LIST,GET) per second do the apiservers get by code?", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + { + "alias": "/2../i", + "color": "#56A64B" + }, + { + "alias": "/3../i", + "color": "#F2CC0C" + }, + { + "alias": "/4../i", + "color": "#3274D9" + }, + { + "alias": "/5../i", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "span": 3, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (code) (code_resource:apiserver_request_total:rate5m{verb=\"read\", cluster=\"$cluster\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}} code {{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Read SLI - Requests", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "How many percent of read requests (LIST,GET) per second are returned with errors (5xx)?", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (resource) (code_resource:apiserver_request_total:rate5m{verb=\"read\",code=~\"5..\", cluster=\"$cluster\"}) / sum by (resource) (code_resource:apiserver_request_total:rate5m{verb=\"read\", cluster=\"$cluster\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}} resource {{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Read SLI - Errors", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "How many seconds is the 99th percentile for reading (LIST|GET) a given resource?", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cluster_quantile:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds:histogram_quantile{verb=\"read\", cluster=\"$cluster\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}} resource {{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Read SLI - Duration", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "decimals": 3, + "description": "How many percent of write requests (POST|PUT|PATCH|DELETE) in 30 days have been answered successfully and fast enough?", + "format": "percentunit", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + + }, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "rightSide": true + }, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "apiserver_request:availability30d{verb=\"write\", cluster=\"$cluster\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Write Availability (30d)", + "tooltip": { + "shared": false + }, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "How many write requests (POST|PUT|PATCH|DELETE) per second do the apiservers get by code?", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + { + "alias": "/2../i", + "color": "#56A64B" + }, + { + "alias": "/3../i", + "color": "#F2CC0C" + }, + { + "alias": "/4../i", + "color": "#3274D9" + }, + { + "alias": "/5../i", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "span": 3, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (code) (code_resource:apiserver_request_total:rate5m{verb=\"write\", cluster=\"$cluster\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}} code {{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Write SLI - Requests", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "How many percent of write requests (POST|PUT|PATCH|DELETE) per second are returned with errors (5xx)?", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 11, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (resource) (code_resource:apiserver_request_total:rate5m{verb=\"write\",code=~\"5..\", cluster=\"$cluster\"}) / sum by (resource) (code_resource:apiserver_request_total:rate5m{verb=\"write\", cluster=\"$cluster\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}} resource {{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Write SLI - Errors", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "How many seconds is the 99th percentile for writing (POST|PUT|PATCH|DELETE) a given resource?", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 12, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cluster_quantile:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds:histogram_quantile{verb=\"write\", cluster=\"$cluster\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}} resource {{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Write SLI - Duration", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 13, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(workqueue_adds_total{job=\"apiserver\", instance=~\"$instance\", cluster=\"$cluster\"}[$__rate_interval])) by (instance, name)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Work Queue Add Rate", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 14, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(workqueue_depth{job=\"apiserver\", instance=~\"$instance\", cluster=\"$cluster\"}[$__rate_interval])) by (instance, name)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Work Queue Depth", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 15, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(workqueue_queue_duration_seconds_bucket{job=\"apiserver\", instance=~\"$instance\", cluster=\"$cluster\"}[$__rate_interval])) by (instance, name, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Work Queue Latency", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 16, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_resident_memory_bytes{job=\"apiserver\",instance=~\"$instance\", cluster=\"$cluster\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 17, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(process_cpu_seconds_total{job=\"apiserver\",instance=~\"$instance\", cluster=\"$cluster\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU usage", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 18, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{job=\"apiserver\",instance=~\"$instance\", cluster=\"$cluster\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": "cluster", + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"apiserver\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(up{job=\"apiserver\", cluster=\"$cluster\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / API server", + "uid": "09ec8aa1e996d6ffcd6817bbaff4db1b", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/cluster-total.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/cluster-total.yaml new file mode 100644 index 0000000000..cf8e00540c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/cluster-total.yaml @@ -0,0 +1,1882 @@ +{{- /* +Generated from 'cluster-total' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "cluster-total" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + cluster-total.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "panels": [ + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 3, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Received", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Transmitted", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "columns": [ + { + "text": "Time", + "value": "Time" + }, + { + "text": "Value #A", + "value": "Value #A" + }, + { + "text": "Value #B", + "value": "Value #B" + }, + { + "text": "Value #C", + "value": "Value #C" + }, + { + "text": "Value #D", + "value": "Value #D" + }, + { + "text": "Value #E", + "value": "Value #E" + }, + { + "text": "Value #F", + "value": "Value #F" + }, + { + "text": "Value #G", + "value": "Value #G" + }, + { + "text": "Value #H", + "value": "Value #H" + }, + { + "text": "namespace", + "value": "namespace" + } + ], + "datasource": "$datasource", + "fill": 1, + "fontSize": "90%", + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 5, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null as zero", + "renderer": "flot", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": false + }, + "spaceLength": 10, + "span": 24, + "styles": [ + { + "alias": "Time", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Time", + "thresholds": [ + + ], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Current Bandwidth Received", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Current Bandwidth Transmitted", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Average Bandwidth Received", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Average Bandwidth Transmitted", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Rate of Received Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Received Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #G", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #H", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Namespace", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "Drill down", + "linkUrl": "d/8b7a8b326d7a6f1f04244066368c67af/kubernetes-networking-namespace-pods?orgId=1&refresh=30s&var-namespace=$__cell", + "pattern": "namespace", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "G", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "H", + "step": 10 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Status", + "type": "table" + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 6, + "panels": [ + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 7, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Rate of Bytes Received", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 8, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Rate of Bytes Transmitted", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Average Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 9, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth History", + "titleSize": "h6", + "type": "row" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 12 + }, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 12, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 13, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 14, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Packets", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 15, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 50 + }, + "id": 16, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 59 + }, + "id": 17, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\".+\"}[$interval:$resolution])) by (namespace))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 59 + }, + "id": 18, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + { + "targetBlank": true, + "title": "What is TCP Retransmit?", + "url": "https://accedian.com/enterprises/blog/network-packet-loss-retransmissions-and-duplicate-acknowledgements/" + } + ], + "minSpan": 24, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(rate(node_netstat_Tcp_RetransSegs{cluster=\"$cluster\"}[$interval:$resolution]) / rate(node_netstat_Tcp_OutSegs{cluster=\"$cluster\"}[$interval:$resolution])) by (instance))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of TCP Retransmits out of all sent segments", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 59 + }, + "id": 19, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [ + { + "targetBlank": true, + "title": "Why monitor SYN retransmits?", + "url": "https://github.com/prometheus/node_exporter/issues/1023#issuecomment-408128365" + } + ], + "minSpan": 24, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(rate(node_netstat_TcpExt_TCPSynRetrans{cluster=\"$cluster\"}[$interval:$resolution]) / rate(node_netstat_Tcp_RetransSegs{cluster=\"$cluster\"}[$interval:$resolution])) by (instance))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of TCP SYN Retransmits out of all retransmits", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Errors", + "titleSize": "h6", + "type": "row" + } + ], + "refresh": "10s", + "rows": [ + + ], + "schemaVersion": 18, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "resolution", + "options": [ + { + "selected": false, + "text": "30s", + "value": "30s" + }, + { + "selected": true, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + } + ], + "query": "30s,5m,1h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "interval", + "options": [ + { + "selected": true, + "text": "4h", + "value": "4h" + } + ], + "query": "4h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + }, + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Networking / Cluster", + "uid": "ff635a025bcfea7bc3dd4f508990a3e9", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/controller-manager.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/controller-manager.yaml new file mode 100644 index 0000000000..507d47555d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/controller-manager.yaml @@ -0,0 +1,1196 @@ +{{- /* +Generated from 'controller-manager' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +{{- if (include "exporter.kubeControllerManager.enabled" .)}} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "controller-manager" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + controller-manager.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + + }, + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "rightSide": true + }, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + {{- if .Values.k3sServer.enabled }} + "expr": "sum(up{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", metrics_path=\"/metrics\"})", + {{- else }} + "expr": "sum(up{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\"})", + {{- end }} + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Up", + "tooltip": { + "shared": false + }, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "min" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(workqueue_adds_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, name)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Work Queue Add Rate", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(workqueue_depth{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, name)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Work Queue Depth", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(workqueue_queue_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, name, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} {{`{{`}}name{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Work Queue Latency", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(rest_client_requests_total{job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\",code=~\"2..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "2xx", + "refId": "A" + }, + { + "expr": "sum(rate(rest_client_requests_total{job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\",code=~\"3..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "3xx", + "refId": "B" + }, + { + "expr": "sum(rate(rest_client_requests_total{job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\",code=~\"4..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "4xx", + "refId": "C" + }, + { + "expr": "sum(rate(rest_client_requests_total{job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\",code=~\"5..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "5xx", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Kube API Request Rate", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 8, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\", verb=\"POST\"}[$__rate_interval])) by (verb, url, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Post Request Latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\", instance=~\"$instance\", verb=\"GET\"}[$__rate_interval])) by (verb, url, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Get Request Latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_resident_memory_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(process_cpu_seconds_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\",instance=~\"$instance\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU usage", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 11, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": "cluster", + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(up{cluster=\"$cluster\", job=\"{{ include "exporter.kubeControllerManager.jobName" . }}\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Controller Manager", + "uid": "72e0e05bef5099e5f049b05fdc429ed4", + "version": 0 + } +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/etcd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/etcd.yaml new file mode 100644 index 0000000000..0eeedc6299 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/etcd.yaml @@ -0,0 +1,1229 @@ +{{- /* +Generated from 'etcd' from https://github.com/etcd-io/etcd.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +{{- if (include "exporter.kubeEtcd.enabled" .)}} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "etcd" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + etcd.json: |- + { + "annotations": { + "list": [] + }, + "description": "etcd sample Grafana dashboard with Prometheus", + "editable": true, + "gnetId": null, + "hideControls": false, + "links": [], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": "$datasource", + "editable": true, + "error": false, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "id": 28, + "interval": null, + "isNew": true, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "targets": [ + { + "expr": "sum(etcd_server_has_leader{job=\"$cluster\"})", + "intervalFactor": 2, + "legendFormat": "", + "metric": "etcd_server_has_leader", + "refId": "A", + "step": 20 + } + ], + "thresholds": "", + "title": "Up", + "type": "singlestat", + "valueFontSize": "200%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fill": 0, + "id": 23, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 5, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(grpc_server_started_total{job=\"$cluster\",grpc_type=\"unary\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "RPC Rate", + "metric": "grpc_server_started_total", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(rate(grpc_server_handled_total{job=\"$cluster\",grpc_type=\"unary\",grpc_code=~\"Unknown|FailedPrecondition|ResourceExhausted|Internal|Unavailable|DataLoss|DeadlineExceeded\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "RPC Failed Rate", + "metric": "grpc_server_handled_total", + "refId": "B", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "RPC Rate", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fill": 0, + "id": 41, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 4, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(grpc_server_started_total{job=\"$cluster\",grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total{job=\"$cluster\",grpc_service=\"etcdserverpb.Watch\",grpc_type=\"bidi_stream\"})", + "intervalFactor": 2, + "legendFormat": "Watch Streams", + "metric": "grpc_server_handled_total", + "refId": "A", + "step": 4 + }, + { + "expr": "sum(grpc_server_started_total{job=\"$cluster\",grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"}) - sum(grpc_server_handled_total{job=\"$cluster\",grpc_service=\"etcdserverpb.Lease\",grpc_type=\"bidi_stream\"})", + "intervalFactor": 2, + "legendFormat": "Lease Streams", + "metric": "grpc_server_handled_total", + "refId": "B", + "step": 4 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Active Streams", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "showTitle": false, + "title": "Row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "decimals": null, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "etcd_mvcc_db_total_size_in_bytes{job=\"$cluster\"}", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} DB Size", + "metric": "", + "refId": "A", + "step": 4 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "DB Size", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 1, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 4, + "stack": false, + "steppedLine": true, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(etcd_disk_wal_fsync_duration_seconds_bucket{job=\"$cluster\"}[$__rate_interval])) by (instance, le))", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} WAL fsync", + "metric": "etcd_disk_wal_fsync_duration_seconds_bucket", + "refId": "A", + "step": 4 + }, + { + "expr": "histogram_quantile(0.99, sum(rate(etcd_disk_backend_commit_duration_seconds_bucket{job=\"$cluster\"}[$__rate_interval])) by (instance, le))", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} DB fsync", + "metric": "etcd_disk_backend_commit_duration_seconds_bucket", + "refId": "B", + "step": 4 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Disk Sync Duration", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fill": 0, + "id": 29, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_resident_memory_bytes{job=\"$cluster\"}", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Resident Memory", + "metric": "process_resident_memory_bytes", + "refId": "A", + "step": 4 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "New row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fill": 5, + "id": 22, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "rate(etcd_network_client_grpc_received_bytes_total{job=\"$cluster\"}[$__rate_interval])", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Client Traffic In", + "metric": "etcd_network_client_grpc_received_bytes_total", + "refId": "A", + "step": 4 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Traffic In", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fill": 5, + "id": 21, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "rate(etcd_network_client_grpc_sent_bytes_total{job=\"$cluster\"}[$__rate_interval])", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Client Traffic Out", + "metric": "etcd_network_client_grpc_sent_bytes_total", + "refId": "A", + "step": 4 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Client Traffic Out", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fill": 0, + "id": 20, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(etcd_network_peer_received_bytes_total{job=\"$cluster\"}[$__rate_interval])) by (instance)", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Peer Traffic In", + "metric": "etcd_network_peer_received_bytes_total", + "refId": "A", + "step": 4 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Peer Traffic In", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "decimals": null, + "editable": true, + "error": false, + "fill": 0, + "grid": {}, + "id": 16, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(etcd_network_peer_sent_bytes_total{job=\"$cluster\"}[$__rate_interval])) by (instance)", + "hide": false, + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Peer Traffic Out", + "metric": "etcd_network_peer_sent_bytes_total", + "refId": "A", + "step": 4 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Peer Traffic Out", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "title": "New row" + }, + { + "collapse": false, + "editable": true, + "height": "250px", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fill": 0, + "id": 40, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(etcd_server_proposals_failed_total{job=\"$cluster\"}[$__rate_interval]))", + "intervalFactor": 2, + "legendFormat": "Proposal Failure Rate", + "metric": "etcd_server_proposals_failed_total", + "refId": "A", + "step": 2 + }, + { + "expr": "sum(etcd_server_proposals_pending{job=\"$cluster\"})", + "intervalFactor": 2, + "legendFormat": "Proposal Pending Total", + "metric": "etcd_server_proposals_pending", + "refId": "B", + "step": 2 + }, + { + "expr": "sum(rate(etcd_server_proposals_committed_total{job=\"$cluster\"}[$__rate_interval]))", + "intervalFactor": 2, + "legendFormat": "Proposal Commit Rate", + "metric": "etcd_server_proposals_committed_total", + "refId": "C", + "step": 2 + }, + { + "expr": "sum(rate(etcd_server_proposals_applied_total{job=\"$cluster\"}[$__rate_interval]))", + "intervalFactor": 2, + "legendFormat": "Proposal Apply Rate", + "refId": "D", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Raft Proposals", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "datasource": "$datasource", + "decimals": 0, + "editable": true, + "error": false, + "fill": 0, + "id": 19, + "isNew": true, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "changes(etcd_server_leader_changes_seen_total{job=\"$cluster\"}[1d])", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Total Leader Elections Per Day", + "metric": "etcd_server_leader_changes_seen_total", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Total Leader Elections Per Day", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": 0, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 28 + }, + "hiddenSeries": false, + "id": 42, + "isNew": true, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum by (instance, le) (rate(etcd_network_peer_round_trip_time_seconds_bucket{job=\"$cluster\"}[$__rate_interval])))", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Peer round trip time", + "metric": "etcd_network_peer_round_trip_time_seconds_bucket", + "refId": "A", + "step": 2 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Peer round trip time", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:925", + "decimals": null, + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:926", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "New row" + } + ], + "schemaVersion": 13, + "sharedCrosshair": false, + "style": "dark", + "tags": [ + "etcd-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "prod", + "value": "prod" + }, + "datasource": "$datasource", + "hide": {{ if (or .Values.grafana.sidecar.dashboards.multicluster.global.enabled .Values.grafana.sidecar.dashboards.multicluster.etcd.enabled) }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": "cluster", + "multi": false, + "name": "cluster", + "options": [], + "query": "label_values(etcd_server_has_leader, job)", + "refresh": 2, + "regex": "", + "sort": 2, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "now": true, + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "etcd", + "uid": "c2f4e12cdf69feb95caa41a5a1b423d9", + "version": 215 + } +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/grafana-overview.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/grafana-overview.yaml new file mode 100644 index 0000000000..f8c8884d0b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/grafana-overview.yaml @@ -0,0 +1,635 @@ +{{- /* +Generated from 'grafana-overview' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "grafana-overview" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + grafana-overview.json: |- + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [ + + ], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 3085, + "iteration": 1631554945276, + "links": [ + + ], + "panels": [ + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "mappings": [ + + ], + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "text": { + + }, + "textMode": "auto" + }, + "pluginVersion": "8.1.3", + "targets": [ + { + "expr": "grafana_alerting_result_total{job=~\"$job\", instance=~\"$instance\", state=\"alerting\"}", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Firing Alerts", + "type": "stat" + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "mappings": [ + + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + + ] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "text": { + + }, + "textMode": "auto" + }, + "pluginVersion": "8.1.3", + "targets": [ + { + "expr": "sum(grafana_stat_totals_dashboard{job=~\"$job\", instance=~\"$instance\"})", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Dashboards", + "type": "stat" + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "displayMode": "auto" + }, + "mappings": [ + + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + + ] + }, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 10, + "options": { + "showHeader": true + }, + "pluginVersion": "8.1.3", + "targets": [ + { + "expr": "grafana_build_info{job=~\"$job\", instance=~\"$instance\"}", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Build Info", + "transformations": [ + { + "id": "labelsToFields", + "options": { + + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "branch": true, + "container": true, + "goversion": true, + "namespace": true, + "pod": true, + "revision": true + }, + "indexByName": { + "Time": 7, + "Value": 11, + "branch": 4, + "container": 8, + "edition": 2, + "goversion": 6, + "instance": 1, + "job": 0, + "namespace": 9, + "pod": 10, + "revision": 5, + "version": 3 + }, + "renameByName": { + + } + } + } + ], + "type": "table" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "links": [ + + ] + }, + "overrides": [ + + ] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 5 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (status_code) (irate(grafana_http_request_duration_seconds_count{job=~\"$job\", instance=~\"$instance\"}[1m])) ", + "interval": "", + "legendFormat": "{{`{{`}}status_code{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeRegions": [ + + ], + "timeShift": null, + "title": "RPS", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "$$hashKey": "object:157", + "format": "reqps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:158", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "links": [ + + ] + }, + "overrides": [ + + ] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 5 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "8.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "exemplar": true, + "expr": "histogram_quantile(0.99, sum(irate(grafana_http_request_duration_seconds_bucket{instance=~\"$instance\", job=~\"$job\"}[$__rate_interval])) by (le)) * 1", + "interval": "", + "legendFormat": "99th Percentile", + "refId": "A" + }, + { + "exemplar": true, + "expr": "histogram_quantile(0.50, sum(irate(grafana_http_request_duration_seconds_bucket{instance=~\"$instance\", job=~\"$job\"}[$__rate_interval])) by (le)) * 1", + "interval": "", + "legendFormat": "50th Percentile", + "refId": "B" + }, + { + "exemplar": true, + "expr": "sum(irate(grafana_http_request_duration_seconds_sum{instance=~\"$instance\", job=~\"$job\"}[$__rate_interval])) * 1 / sum(irate(grafana_http_request_duration_seconds_count{instance=~\"$instance\", job=~\"$job\"}[$__rate_interval]))", + "interval": "", + "legendFormat": "Average", + "refId": "C" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeRegions": [ + + ], + "timeShift": null, + "title": "Request Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "$$hashKey": "object:210", + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:211", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "schemaVersion": 30, + "style": "dark", + "tags": [ + + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": [ + "default/grafana" + ], + "value": [ + "default/grafana" + ] + }, + "datasource": "$datasource", + "definition": "label_values(grafana_build_info, job)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "job", + "options": [ + + ], + "query": { + "query": "label_values(grafana_build_info, job)", + "refId": "Billing Admin-job-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "definition": "label_values(grafana_build_info, instance)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "instance", + "options": [ + + ], + "query": { + "query": "label_values(grafana_build_info, instance)", + "refId": "Billing Admin-instance-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Grafana Overview", + "uid": "6be0s85Mk", + "version": 2 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-coredns.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-coredns.yaml new file mode 100644 index 0000000000..7ecca76f23 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-coredns.yaml @@ -0,0 +1,1534 @@ +{{- /* +Generated from 'k8s-coredns' from ../files/dashboards/k8s-coredns.json +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.coreDns.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-coredns" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-coredns.json: |- + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A dashboard for the CoreDNS DNS server with updated metrics for version 1.7.0+. Based on the CoreDNS dashboard by buhay.", + "editable": true, + "gnetId": 12539, + "graphTooltip": 0, + "iteration": 1603798405693, + "links": [ + { + "icon": "external link", + "tags": [], + "targetBlank": true, + "title": "CoreDNS.io", + "type": "link", + "url": "https://coredns.io" + } + ], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(coredns_dns_request_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (proto) or\nsum(rate(coredns_dns_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (proto)", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}", + "refId": "A", + "step": 60 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests (total)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total", + "yaxis": 2 + }, + { + "alias": "other", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(coredns_dns_request_type_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (type) or \nsum(rate(coredns_dns_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (type)", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{type}}"}}", + "refId": "A", + "step": 60 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests (by qtype)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(coredns_dns_request_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (zone) or\nsum(rate(coredns_dns_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (zone)", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{zone}}"}}", + "refId": "A", + "step": 60 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests (by zone)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 7 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(coredns_dns_request_do_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) or\nsum(rate(coredns_dns_do_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m]))", + "interval": "", + "intervalFactor": 2, + "legendFormat": "DO", + "refId": "A", + "step": 40 + }, + { + "expr": "sum(rate(coredns_dns_request_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) or\nsum(rate(coredns_dns_requests_total{job=\"coredns\",instance=~\"$instance\"}[5m]))", + "interval": "", + "intervalFactor": 2, + "legendFormat": "total", + "refId": "B", + "step": 40 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests (DO bit)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 7 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "tcp:90", + "yaxis": 2 + }, + { + "alias": "tcp:99 ", + "yaxis": 2 + }, + { + "alias": "tcp:50", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto))", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:99 ", + "refId": "A", + "step": 60 + }, + { + "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto))", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:90", + "refId": "B", + "step": 60 + }, + { + "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto))", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:50", + "refId": "C", + "step": 60 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests (size, udp)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 7 + }, + "hiddenSeries": false, + "id": 12, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "tcp:90", + "yaxis": 1 + }, + { + "alias": "tcp:99 ", + "yaxis": 1 + }, + { + "alias": "tcp:50", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:99 ", + "refId": "A", + "step": 60 + }, + { + "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:90", + "refId": "B", + "step": 60 + }, + { + "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_request_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto))", + "format": "time_series", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:50", + "refId": "C", + "step": 60 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Requests (size,tcp)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(coredns_dns_response_rcode_count_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (rcode) or\nsum(rate(coredns_dns_responses_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (rcode)", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{rcode}}"}}", + "refId": "A", + "step": 40 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Responses (by rcode)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 14 + }, + "hiddenSeries": false, + "id": 32, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_request_duration_seconds_bucket{job=\"coredns\",instance=~\"$instance\"}[5m])) by (le, job))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "99%", + "refId": "A", + "step": 40 + }, + { + "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_request_duration_seconds_bucket{job=\"coredns\",instance=~\"$instance\"}[5m])) by (le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "90%", + "refId": "B", + "step": 40 + }, + { + "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_request_duration_seconds_bucket{job=\"coredns\",instance=~\"$instance\"}[5m])) by (le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "50%", + "refId": "C", + "step": 40 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Responses (duration)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "s", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 21 + }, + "hiddenSeries": false, + "id": 18, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "udp:50%", + "yaxis": 1 + }, + { + "alias": "tcp:50%", + "yaxis": 2 + }, + { + "alias": "tcp:90%", + "yaxis": 2 + }, + { + "alias": "tcp:99%", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto)) ", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:99%", + "refId": "A", + "step": 40 + }, + { + "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto)) ", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:90%", + "refId": "B", + "step": 40 + }, + { + "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"udp\"}[5m])) by (le,proto)) ", + "hide": false, + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:50%", + "metric": "", + "refId": "C", + "step": 40 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Responses (size, udp)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 21 + }, + "hiddenSeries": false, + "id": 20, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "udp:50%", + "yaxis": 1 + }, + { + "alias": "tcp:50%", + "yaxis": 1 + }, + { + "alias": "tcp:90%", + "yaxis": 1 + }, + { + "alias": "tcp:99%", + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto)) ", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:99%", + "refId": "A", + "step": 40 + }, + { + "expr": "histogram_quantile(0.90, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le,proto)) ", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:90%", + "refId": "B", + "step": 40 + }, + { + "expr": "histogram_quantile(0.50, sum(rate(coredns_dns_response_size_bytes_bucket{job=\"coredns\",instance=~\"$instance\",proto=\"tcp\"}[5m])) by (le, proto)) ", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{"{{proto}}"}}:50%", + "metric": "", + "refId": "C", + "step": 40 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Responses (size, tcp)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 28 + }, + "hiddenSeries": false, + "id": 22, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(coredns_cache_size{job=\"coredns\",instance=~\"$instance\"}) by (type) or\nsum(coredns_cache_entries{job=\"coredns\",instance=~\"$instance\"}) by (type)", + "interval": "", + "intervalFactor": 2, + "legendFormat": "{{"{{type}}"}}", + "refId": "A", + "step": 40 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cache (size)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {}, + "links": [] + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 28 + }, + "hiddenSeries": false, + "id": 24, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.2.0", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "misses", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(coredns_cache_hits_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (type)", + "hide": false, + "intervalFactor": 2, + "legendFormat": "hits:{{"{{type}}"}}", + "refId": "A", + "step": 40 + }, + { + "expr": "sum(rate(coredns_cache_misses_total{job=\"coredns\",instance=~\"$instance\"}[5m])) by (type)", + "hide": false, + "intervalFactor": 2, + "legendFormat": "misses", + "refId": "B", + "step": 40 + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cache (hitrate)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "10s", + "schemaVersion": 26, + "style": "dark", + "tags": [ + "dns", + "coredns" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "includeAll": false, + "label": "Data Source", + "multi": false, + "name": "datasource", + "options": [], + "query": "prometheus", + "queryValue": "", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "definition": "label_values(up{job=\"coredns\"}, instance)", + "hide": 0, + "includeAll": true, + "label": "Instance", + "multi": false, + "name": "instance", + "options": [], + "query": "label_values(up{job=\"coredns\"}, instance)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 3, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-3h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "CoreDNS", + "uid": "vkQ0UHxik", + "version": 2 + } +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-cluster.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-cluster.yaml new file mode 100644 index 0000000000..5c1193274e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-cluster.yaml @@ -0,0 +1,3088 @@ +{{- /* +Generated from 'k8s-resources-cluster' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-cluster" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-cluster.json: |- + { + "annotations": { + "list": [ + + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "height": "100px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 1, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 2, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cluster:node_cpu:ratio_rate5m{cluster=\"$cluster\"}", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "CPU Utilisation", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 2, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(namespace_cpu:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\",resource=\"cpu\",cluster=\"$cluster\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "CPU Requests Commitment", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 2, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(namespace_cpu:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\",resource=\"cpu\",cluster=\"$cluster\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "CPU Limits Commitment", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 2, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "1 - sum(:node_memory_MemAvailable_bytes:sum{cluster=\"$cluster\"}) / sum(node_memory_MemTotal_bytes{job=\"node-exporter\",cluster=\"$cluster\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "Memory Utilisation", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 2, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(namespace_memory:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\",resource=\"memory\",cluster=\"$cluster\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "Memory Requests Commitment", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 2, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(namespace_memory:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\",resource=\"memory\",cluster=\"$cluster\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "Memory Limits Commitment", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Headlines", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\"}) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Pods", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell_1", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Workloads", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to workloads", + "linkUrl": "d/a87fb0d919ec0ea5f6543124e16c42a5/k8s-resources-workloads-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell_1", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "CPU Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #G", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Namespace", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell", + "pattern": "namespace", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(kube_pod_owner{job=\"kube-state-metrics\", cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "count(avg(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\"}) by (workload, namespace)) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(namespace_cpu:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\"}) by (namespace) / sum(namespace_cpu:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(namespace_cpu:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\"}) by (namespace) / sum(namespace_cpu:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "G", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_rss{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", container!=\"\"}) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Usage (w/o cache)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Pods", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell_1", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Workloads", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to workloads", + "linkUrl": "d/a87fb0d919ec0ea5f6543124e16c42a5/k8s-resources-workloads-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell_1", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Memory Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #G", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Namespace", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell", + "pattern": "namespace", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(kube_pod_owner{job=\"kube-state-metrics\", cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "count(avg(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\"}) by (workload, namespace)) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(container_memory_rss{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", container!=\"\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(namespace_memory:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(container_memory_rss{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", container!=\"\"}) by (namespace) / sum(namespace_memory:kube_pod_container_resource_requests:sum{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(namespace_memory:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + }, + { + "expr": "sum(container_memory_rss{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", container!=\"\"}) by (namespace) / sum(namespace_memory:kube_pod_container_resource_limits:sum{cluster=\"$cluster\"}) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "G", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Requests by Namespace", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Requests", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 11, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Current Receive Bandwidth", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Current Transmit Bandwidth", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Rate of Received Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Received Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Namespace", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell", + "pattern": "namespace", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Network Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Network Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 12, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 13, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 14, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Container Bandwidth by Namespace: Received", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 15, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "avg(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Container Bandwidth by Namespace: Transmitted", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Average Container Bandwidth by Namespace", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 16, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 17, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 18, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 19, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=~\".+\"}[$__rate_interval])) by (namespace)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets Dropped", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": -1, + "fill": 10, + "id": 20, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "ceil(sum by(namespace) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "IOPS(Reads+Writes)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 21, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(namespace) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}namespace{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "ThroughPut(Read+Write)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Storage IO", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 22, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "sort": { + "col": 4, + "desc": true + }, + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "IOPS(Reads)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "IOPS(Writes)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "IOPS(Reads + Writes)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Throughput(Read)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Throughput(Write)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Throughput(Read + Write)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Namespace", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/85a562078cdf77779eaa1add43ccec1e/k8s-resources-namespace?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$__cell", + "pattern": "namespace", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum by(namespace) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum by(namespace) (rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum by(namespace) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum by(namespace) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum by(namespace) (rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum by(namespace) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace!=\"\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Storage IO", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Storage IO - Distribution", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Compute Resources / Cluster", + "uid": "efa86fd1d0c121a26444b636a3f509a8", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-multicluster.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-multicluster.yaml new file mode 100644 index 0000000000..75e1584201 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-multicluster.yaml @@ -0,0 +1,24 @@ +{{- /* +Generated from 'k8s-resources-multicluster' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-multicluster" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-multicluster.json: |- + {{`{"editable":`}}{{ .Values.grafana.defaultDashboardsEditable }}{{`,"panels":[{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"none"}},"gridPos":{"h":3,"w":4,"x":0,"y":0},"id":1,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"cluster:node_cpu:ratio_rate5m","instant":true}],"title":"CPU Utilisation","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":4,"y":0},"id":2,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", resource=\"cpu\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\", resource=\"cpu\"})","instant":true}],"title":"CPU Requests Commitment","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":8,"y":0},"id":3,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", resource=\"cpu\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\", resource=\"cpu\"})","instant":true}],"title":"CPU Limits Commitment","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":12,"y":0},"id":4,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"1 - sum(:node_memory_MemAvailable_bytes:sum) / sum(node_memory_MemTotal_bytes{job=\"node-exporter\"})","instant":true}],"title":"Memory Utilisation","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":16,"y":0},"id":5,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", resource=\"memory\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\", resource=\"memory\"})","instant":true}],"title":"Memory Requests Commitment","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":20,"y":0},"id":6,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", resource=\"memory\"}) / sum(kube_node_status_allocatable{job=\"kube-state-metrics\", resource=\"memory\"})","instant":true}],"title":"Memory Limits Commitment","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"showPoints":"never"}}},"gridPos":{"h":7,"w":24,"x":0,"y":1},"id":7,"interval":"1m","options":{"legend":{"asTable":true,"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate) by (cluster)","legendFormat":"__auto"}],"title":"CPU Usage","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"overrides":[{"matcher":{"id":"byRegexp","options":"/%/"},"properties":[{"id":"unit","value":"percentunit"}]},{"matcher":{"id":"byName","options":"Cluster"},"properties":[{"id":"links","value":[{"title":"Drill down","url":"/d/efa86fd1d0c121a26444b636a3f509a8/kubernetes-compute-resources-cluster?${datasource:queryparam}&var-cluster=${__data.fields.Cluster}"}]}]}]},"gridPos":{"h":7,"w":24,"x":0,"y":2},"id":8,"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate) by (cluster)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", resource=\"cpu\"}) by (cluster)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate) by (cluster) / sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", resource=\"cpu\"}) by (cluster)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", resource=\"cpu\"}) by (cluster)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate) by (cluster) / sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", resource=\"cpu\"}) by (cluster)","format":"table","instant":true}],"title":"CPU Quota","transformations":[{"id":"joinByField","options":{"byField":"cluster","mode":"outer"}},{"id":"organize","options":{"excludeByName":{"Time":true,"Time 1":true,"Time 2":true,"Time 3":true,"Time 4":true,"Time 5":true},"indexByName":{"Time 1":0,"Time 2":1,"Time 3":2,"Time 4":3,"Time 5":4,"Value #A":6,"Value #B":7,"Value #C":8,"Value #D":9,"Value #E":10,"cluster":5},"renameByName":{"Value #A":"CPU Usage","Value #B":"CPU Requests","Value #C":"CPU Requests %","Value #D":"CPU Limits","Value #E":"CPU Limits %","cluster":"Cluster"}}}],"type":"table"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"showPoints":"never"},"unit":"bytes"}},"gridPos":{"h":7,"w":24,"x":0,"y":3},"id":9,"interval":"1m","options":{"legend":{"asTable":true,"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\"}) by (cluster)","legendFormat":"__auto"}],"title":"Memory Usage (w/o cache)","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"bytes"},"overrides":[{"matcher":{"id":"byRegexp","options":"/%/"},"properties":[{"id":"unit","value":"percentunit"}]},{"matcher":{"id":"byName","options":"Cluster"},"properties":[{"id":"links","value":[{"title":"Drill down","url":"/d/efa86fd1d0c121a26444b636a3f509a8/kubernetes-compute-resources-cluster?${datasource:queryparam}&var-cluster=${__data.fields.Cluster}"}]}]}]},"gridPos":{"h":7,"w":24,"x":0,"y":4},"id":10,"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\"}) by (cluster)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", resource=\"memory\"}) by (cluster)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\"}) by (cluster) / sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", resource=\"memory\"}) by (cluster)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", resource=\"memory\"}) by (cluster)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(container_memory_rss{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", container!=\"\"}) by (cluster) / sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", resource=\"memory\"}) by (cluster)","format":"table","instant":true}],"title":"Memory Requests by Cluster","transformations":[{"id":"joinByField","options":{"byField":"cluster","mode":"outer"}},{"id":"organize","options":{"excludeByName":{"Time":true,"Time 1":true,"Time 2":true,"Time 3":true,"Time 4":true,"Time 5":true},"indexByName":{"Time 1":0,"Time 2":1,"Time 3":2,"Time 4":3,"Time 5":4,"Value #A":6,"Value #B":7,"Value #C":8,"Value #D":9,"Value #E":10,"cluster":5},"renameByName":{"Value #A":"Memory Usage","Value #B":"Memory Requests","Value #C":"Memory Requests %","Value #D":"Memory Limits","Value #E":"Memory Limits %","cluster":"Cluster"}}}],"type":"table"}],"refresh":"10s","schemaVersion":39,"tags":["kubernetes-mixin"],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"label":"Data source","name":"datasource","query":"prometheus","regex":"","type":"datasource"}]},"time":{"from":"now-1h","to":"now"},"timezone": "`}}{{ .Values.grafana.defaultDashboardsTimezone }}{{`","title":"Kubernetes / Compute Resources / Multi-Cluster","uid":"b59e6c9f2fcbe2e16d77fc492374cc4f"}`}} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-namespace.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-namespace.yaml new file mode 100644 index 0000000000..896b0b2d92 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-namespace.yaml @@ -0,0 +1,2797 @@ +{{- /* +Generated from 'k8s-resources-namespace' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-namespace" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-namespace.json: |- + { + "annotations": { + "list": [ + + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "height": "100px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 1, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) / sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "CPU Utilisation (from requests)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) / sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "CPU Utilisation (from limits)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) / sum(kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "Memory Utilisation (from requests)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "format": "percentunit", + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) / sum(kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"})", + "format": "time_series", + "instant": true, + "intervalFactor": 2, + "refId": "A" + } + ], + "thresholds": "70,80", + "timeFrom": null, + "timeShift": null, + "title": "Memory Utilisation (from limits)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "singlestat", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Headlines", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "quota - requests", + "color": "#F2495C", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + }, + { + "alias": "quota - limits", + "color": "#FF9830", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"requests.cpu\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "quota - requests", + "legendLink": null, + "step": 10 + }, + { + "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"limits.cpu\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "quota - limits", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "CPU Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "CPU Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "quota - requests", + "color": "#F2495C", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + }, + { + "alias": "quota - limits", + "color": "#FF9830", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"requests.memory\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "quota - requests", + "legendLink": null, + "step": 10 + }, + { + "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"limits.memory\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "quota - limits", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Usage (w/o cache)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Memory Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Usage (RSS)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Usage (Cache)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #G", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Usage (Swap)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #H", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) by (pod) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\", image!=\"\"}) by (pod) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(container_memory_rss{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + }, + { + "expr": "sum(container_memory_cache{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "G", + "step": 10 + }, + { + "expr": "sum(container_memory_swap{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\",container!=\"\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "H", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Current Receive Bandwidth", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Current Transmit Bandwidth", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Rate of Received Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Received Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Network Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Network Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 11, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 12, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 13, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 14, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 15, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets Dropped", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": -1, + "fill": 10, + "id": 16, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "ceil(sum by(pod) (rate(container_fs_reads_total{container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]) + rate(container_fs_writes_total{container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "IOPS(Reads+Writes)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 17, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{container!=\"\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "ThroughPut(Read+Write)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Storage IO", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 18, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "sort": { + "col": 4, + "desc": true + }, + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "IOPS(Reads)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "IOPS(Writes)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "IOPS(Reads + Writes)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Throughput(Read)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Throughput(Write)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Throughput(Read + Write)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum by(pod) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum by(pod) (rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum by(pod) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum by(pod) (rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Storage IO", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Storage IO - Distribution", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(kube_namespace_status_phase{job=\"kube-state-metrics\", cluster=\"$cluster\"}, namespace)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Compute Resources / Namespace (Pods)", + "uid": "85a562078cdf77779eaa1add43ccec1e", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-node.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-node.yaml new file mode 100644 index 0000000000..ab9c76efe0 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-node.yaml @@ -0,0 +1,1026 @@ +{{- /* +Generated from 'k8s-resources-node' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-node" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-node.json: |- + { + "annotations": { + "list": [ + + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 1, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "max capacity", + "color": "#F2495C", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(kube_node_status_capacity{cluster=\"$cluster\", node=~\"$node\", resource=\"cpu\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "max capacity", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "CPU Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "CPU Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", node=~\"$node\"}) by (pod) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", node=~\"$node\"}) by (pod) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "max capacity", + "color": "#F2495C", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(kube_node_status_capacity{cluster=\"$cluster\", node=~\"$node\", resource=\"memory\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "max capacity", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_memory_working_set_bytes{cluster=\"$cluster\", node=~\"$node\", container!=\"\"}) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Usage (w/o cache)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Memory Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Usage (RSS)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Usage (Cache)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #G", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Usage (Swap)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #H", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_memory_working_set_bytes{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_memory_working_set_bytes{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_memory_working_set_bytes{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", node=~\"$node\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_memory_rss{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_memory_cache{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "G", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_memory_swap{cluster=\"$cluster\", node=~\"$node\",container!=\"\"}) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "H", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Quota", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": true, + "name": "node", + "options": [ + + ], + "query": "label_values(kube_node_info{cluster=\"$cluster\"}, node)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Compute Resources / Node (Pods)", + "uid": "200ac8fdbfbb74b39aff88118e4d1c2c", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-pod.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-pod.yaml new file mode 100644 index 0000000000..0a6da86c15 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-pod.yaml @@ -0,0 +1,2469 @@ +{{- /* +Generated from 'k8s-resources-pod' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-pod" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-pod.json: |- + { + "annotations": { + "list": [ + + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 1, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "requests", + "color": "#F2495C", + "fill": 0, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + }, + { + "alias": "limits", + "color": "#FF9830", + "fill": 0, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{namespace=\"$namespace\", pod=\"$pod\", cluster=\"$cluster\"}) by (container)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}container{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"cpu\"}\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "requests", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"cpu\"}\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "limits", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(container_cpu_cfs_throttled_periods_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", cluster=\"$cluster\"}[$__rate_interval])) by (container) /sum(increase(container_cpu_cfs_periods_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", cluster=\"$cluster\"}[$__rate_interval])) by (container)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}container{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.25, + "yaxis": "left" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Throttling", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Throttling", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "CPU Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "CPU Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Container", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "container", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "requests", + "color": "#F2495C", + "dashes": true, + "fill": 0, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + }, + { + "alias": "limits", + "color": "#FF9830", + "dashes": true, + "fill": 0, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}container{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"memory\"}\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "requests", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", resource=\"memory\"}\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "limits", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Usage (WSS)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Memory Usage (WSS)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Usage (RSS)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Usage (Cache)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #G", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Usage (Swap)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #H", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Container", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "container", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", image!=\"\"}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_requests{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container!=\"\", image!=\"\"}) by (container) / sum(cluster:namespace:pod_memory:active:kube_pod_container_resource_limits{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(container_memory_rss{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + }, + { + "expr": "sum(container_memory_cache{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "G", + "step": 10 + }, + { + "expr": "sum(container_memory_swap{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\", container != \"\", container != \"POD\"}) by (container)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "H", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 11, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])) by (pod)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets Dropped", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": -1, + "fill": 10, + "id": 12, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "ceil(sum by(pod) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Reads", + "legendLink": null, + "step": 10 + }, + { + "expr": "ceil(sum by(pod) (rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\",namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Writes", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "IOPS", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 13, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(pod) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Reads", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum by(pod) (rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=~\"$pod\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Writes", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "ThroughPut", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Storage IO - Distribution(Pod - Read & Writes)", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "decimals": -1, + "fill": 10, + "id": 14, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "ceil(sum by(container) (rate(container_fs_reads_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval])))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}container{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "IOPS(Reads+Writes)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 15, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}container{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "ThroughPut(Read+Write)", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Storage IO - Distribution(Containers)", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 16, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "sort": { + "col": 4, + "desc": true + }, + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "IOPS(Reads)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "IOPS(Writes)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "IOPS(Reads + Writes)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": -1, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Throughput(Read)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Throughput(Write)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Throughput(Read + Write)", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Container", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "container", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum by(container) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum by(container) (rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\",device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum by(container) (rate(container_fs_reads_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum by(container) (rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum by(container) (rate(container_fs_reads_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]) + rate(container_fs_writes_bytes_total{job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\", container!=\"\", cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[$__rate_interval]))", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Storage IO", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Storage IO - Distribution", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(kube_namespace_status_phase{job=\"kube-state-metrics\", cluster=\"$cluster\"}, namespace)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "pod", + "options": [ + + ], + "query": "label_values(kube_pod_info{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\"}, pod)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Compute Resources / Pod", + "uid": "6581e46e4e5c7ba40a07646395ef7b23", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-cluster.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-cluster.yaml new file mode 100644 index 0000000000..6def97a796 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-cluster.yaml @@ -0,0 +1,24 @@ +{{- /* +Generated from 'k8s-resources-windows-cluster' from https://github.com/kubernetes-monitoring/kubernetes-mixin.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.windowsMonitoring.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-windows-cluster" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-windows-cluster.json: |- + {{`{"editable":`}}{{ .Values.grafana.defaultDashboardsEditable }}{{`,"panels":[{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"none"}},"gridPos":{"h":3,"w":4,"x":0,"y":0},"id":1,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"1 - avg(rate(windows_cpu_time_total{cluster=\"$cluster\", job=\"windows-exporter\", mode=\"idle\"}[1m]))","instant":true}],"title":"CPU Utilisation","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":4,"y":0},"id":2,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_cpu_cores_request{cluster=\"$cluster\"}) / sum(node:windows_node_num_cpu:sum{cluster=\"$cluster\"})","instant":true}],"title":"CPU Requests Commitment","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":8,"y":0},"id":3,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_cpu_cores_limit{cluster=\"$cluster\"}) / sum(node:windows_node_num_cpu:sum{cluster=\"$cluster\"})","instant":true}],"title":"CPU Limits Commitment","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":12,"y":0},"id":4,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"1 - sum(:windows_node_memory_MemFreeCached_bytes:sum{cluster=\"$cluster\"}) / sum(:windows_node_memory_MemTotal_bytes:sum{cluster=\"$cluster\"})","instant":true}],"title":"Memory Utilisation","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":16,"y":0},"id":5,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_memory_request{cluster=\"$cluster\"}) / sum(:windows_node_memory_MemTotal_bytes:sum{cluster=\"$cluster\"})","instant":true}],"title":"Memory Requests Commitment","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"percentunit"}},"gridPos":{"h":3,"w":4,"x":20,"y":0},"id":6,"interval":"1m","options":{"colorMode":"none"},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_memory_limit{cluster=\"$cluster\"}) / sum(:windows_node_memory_MemTotal_bytes:sum{cluster=\"$cluster\"})","instant":true}],"title":"Memory Limits Commitment","type":"stat"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true}}},"gridPos":{"h":7,"w":24,"x":0,"y":7},"id":7,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\"}) by (namespace)","legendFormat":"__auto"}],"title":"CPU Usage","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"overrides":[{"matcher":{"id":"byRegexp","options":"/%/"},"properties":[{"id":"unit","value":"percentunit"}]},{"matcher":{"id":"byName","options":"Namespace"},"properties":[{"id":"links","value":[{"title":"Drill down to pods","url":"/d/490b402361724ab1d4c45666c1fa9b6f/k8s-resources-windows-namespace?${datasource:queryparam}&var-cluster=$cluster&var-namespace=${__data.fields.Namespace}"}]}]}]},"gridPos":{"h":7,"w":24,"x":0,"y":14},"id":8,"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_cpu_cores_request{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\"}) by (namespace) / sum(kube_pod_windows_container_resource_cpu_cores_request{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_cpu_cores_limit{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\"}) by (namespace) / sum(kube_pod_windows_container_resource_cpu_cores_limit{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true}],"title":"CPU Quota","transformations":[{"id":"joinByField","options":{"byField":"namespace","mode":"outer"}},{"id":"organize","options":{"excludeByName":{"Time":true,"Time 1":true,"Time 2":true,"Time 3":true,"Time 4":true,"Time 5":true},"indexByName":{"Time 1":0,"Time 2":1,"Time 3":2,"Time 4":3,"Time 5":4,"Value #A":6,"Value #B":7,"Value #C":8,"Value #D":9,"Value #E":10,"namespace":5},"renameByName":{"Value #A":"CPU Usage","Value #B":"CPU Requests","Value #C":"CPU Requests %","Value #D":"CPU Limits","Value #E":"CPU Limits %","namespace":"Namespace"}}}],"type":"table"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"decbytes"}},"gridPos":{"h":7,"w":24,"x":0,"y":21},"id":9,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\"}) by (namespace)","legendFormat":"__auto"}],"title":"Memory Usage (Private Working Set)","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"bytes"},"overrides":[{"matcher":{"id":"byRegexp","options":"/%/"},"properties":[{"id":"unit","value":"percentunit"}]},{"matcher":{"id":"byName","options":"Memory Usage"},"properties":[{"id":"unit","value":"decbytes"}]},{"matcher":{"id":"byName","options":"Memory Requests"},"properties":[{"id":"unit","value":"decbytes"}]},{"matcher":{"id":"byName","options":"Memory Limits"},"properties":[{"id":"unit","value":"decbytes"}]},{"matcher":{"id":"byName","options":"Namespace"},"properties":[{"id":"links","value":[{"title":"Drill down to pods","url":"/d/490b402361724ab1d4c45666c1fa9b6f/k8s-resources-windows-namespace?${datasource:queryparam}&var-cluster=$cluster&var-namespace=${__data.fields.Namespace}"}]}]}]},"gridPos":{"h":7,"w":24,"x":0,"y":28},"id":10,"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_memory_request{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\"}) by (namespace) / sum(kube_pod_windows_container_resource_memory_request{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_memory_limit{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\"}) by (namespace) / sum(kube_pod_windows_container_resource_memory_limit{cluster=\"$cluster\"}) by (namespace)","format":"table","instant":true}],"title":"Memory Requests by Namespace","transformations":[{"id":"joinByField","options":{"byField":"namespace","mode":"outer"}},{"id":"organize","options":{"excludeByName":{"Time":true,"Time 1":true,"Time 2":true,"Time 3":true,"Time 4":true,"Time 5":true},"indexByName":{"Time 1":0,"Time 2":1,"Time 3":2,"Time 4":3,"Time 5":4,"Value #A":6,"Value #B":7,"Value #C":8,"Value #D":9,"Value #E":10,"namespace":5},"renameByName":{"Value #A":"Memory Usage","Value #B":"Memory Requests","Value #C":"Memory Requests %","Value #D":"Memory Limits","Value #E":"Memory Limits %","namespace":"Namespace"}}}],"type":"table"}],"refresh":"10s","schemaVersion":39,"tags":["kubernetes-mixin"],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"label":"Data source","name":"datasource","query":"prometheus","regex":"","type":"datasource"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":`}}{{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}{{`,"label":"cluster","name":"cluster","query":"label_values(up{job=\"windows-exporter\"}, cluster)","refresh":2,"sort":1,"type":"query","allValue":".*"}]},"time":{"from":"now-1h","to":"now"},"timezone": "`}}{{ .Values.grafana.defaultDashboardsTimezone }}{{`","title":"Kubernetes / Compute Resources / Cluster(Windows)","uid":"4d08557fd9391b100730f2494bccac68"}`}} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-namespace.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-namespace.yaml new file mode 100644 index 0000000000..2dfd58bed1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-namespace.yaml @@ -0,0 +1,24 @@ +{{- /* +Generated from 'k8s-resources-windows-namespace' from https://github.com/kubernetes-monitoring/kubernetes-mixin.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.windowsMonitoring.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-windows-namespace" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-windows-namespace.json: |- + {{`{"editable":`}}{{ .Values.grafana.defaultDashboardsEditable }}{{`,"panels":[{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true}}},"gridPos":{"h":7,"w":24,"x":0,"y":0},"id":1,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","legendFormat":"__auto"}],"title":"CPU Usage","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"overrides":[{"matcher":{"id":"byRegexp","options":"/%/"},"properties":[{"id":"unit","value":"percentunit"}]},{"matcher":{"id":"byName","options":"Pod"},"properties":[{"id":"links","value":[{"title":"Drill down to pods","url":"/d/40597a704a610e936dc6ed374a7ce023/k8s-resources-windows-pod?${datasource:queryparam}&var-cluster=$cluster&var-namespace=$namespace&var-pod=${__data.fields.Pod}"}]}]}]},"gridPos":{"h":7,"w":24,"x":0,"y":7},"id":2,"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_cpu_cores_request{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod) / sum(kube_pod_windows_container_resource_cpu_cores_request{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_cpu_cores_limit{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod) / sum(kube_pod_windows_container_resource_cpu_cores_limit{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true}],"title":"CPU Quota","transformations":[{"id":"joinByField","options":{"byField":"pod","mode":"outer"}},{"id":"organize","options":{"excludeByName":{"Time":true,"Time 1":true,"Time 2":true,"Time 3":true,"Time 4":true,"Time 5":true},"indexByName":{"Time 1":0,"Time 2":1,"Time 3":2,"Time 4":3,"Time 5":4,"Value #A":6,"Value #B":7,"Value #C":8,"Value #D":9,"Value #E":10,"pod":5},"renameByName":{"Value #A":"CPU Usage","Value #B":"CPU Requests","Value #C":"CPU Requests %","Value #D":"CPU Limits","Value #E":"CPU Limits %","pod":"Pod"}}}],"type":"table"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"decbytes"}},"gridPos":{"h":7,"w":24,"x":0,"y":14},"id":3,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","legendFormat":"__auto"}],"title":"Memory Usage (Private Working Set)","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"bytes"},"overrides":[{"matcher":{"id":"byRegexp","options":"/%/"},"properties":[{"id":"unit","value":"percentunit"}]},{"matcher":{"id":"byName","options":"Pod"},"properties":[{"id":"links","value":[{"title":"Drill down to pods","url":"/d/40597a704a610e936dc6ed374a7ce023/k8s-resources-windows-pod?${datasource:queryparam}&var-cluster=$cluster&var-namespace=$namespace&var-pod=${__data.fields.Pod}"}]}]}]},"gridPos":{"h":7,"w":24,"x":0,"y":21},"id":4,"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_memory_request{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod) / sum(kube_pod_windows_container_resource_memory_request{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_memory_limit{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod) / sum(kube_pod_windows_container_resource_memory_limit{cluster=\"$cluster\", namespace=\"$namespace\"}) by (pod)","format":"table","instant":true}],"title":"Memory Quota","transformations":[{"id":"joinByField","options":{"byField":"pod","mode":"outer"}},{"id":"organize","options":{"excludeByName":{"Time":true,"Time 1":true,"Time 2":true,"Time 3":true,"Time 4":true,"Time 5":true},"indexByName":{"Time 1":0,"Time 2":1,"Time 3":2,"Time 4":3,"Time 5":4,"Value #A":6,"Value #B":7,"Value #C":8,"Value #D":9,"Value #E":10,"pod":5},"renameByName":{"Value #A":"Memory Usage","Value #B":"Memory Requests","Value #C":"Memory Requests %","Value #D":"Memory Limits","Value #E":"Memory Limits %","pod":"Pod"}}}],"type":"table"}],"refresh":"10s","schemaVersion":39,"tags":["kubernetes-mixin"],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"label":"Data source","name":"datasource","query":"prometheus","regex":"","type":"datasource"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":`}}{{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}{{`,"label":"cluster","name":"cluster","query":"label_values(up{job=\"windows-exporter\"}, cluster)","refresh":2,"sort":1,"type":"query","allValue":".*"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":0,"label":"namespace","name":"namespace","query":"label_values(windows_pod_container_available{cluster=\"$cluster\"}, namespace)","refresh":2,"sort":1,"type":"query"}]},"time":{"from":"now-1h","to":"now"},"timezone": "`}}{{ .Values.grafana.defaultDashboardsTimezone }}{{`","title":"Kubernetes / Compute Resources / Namespace(Windows)","uid":"490b402361724ab1d4c45666c1fa9b6f"}`}} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-pod.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-pod.yaml new file mode 100644 index 0000000000..4417b31a6e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-windows-pod.yaml @@ -0,0 +1,24 @@ +{{- /* +Generated from 'k8s-resources-windows-pod' from https://github.com/kubernetes-monitoring/kubernetes-mixin.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.windowsMonitoring.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-windows-pod" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-windows-pod.json: |- + {{`{"editable":`}}{{ .Values.grafana.defaultDashboardsEditable }}{{`,"panels":[{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true}}},"gridPos":{"h":7,"w":24,"x":0,"y":0},"id":1,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","legendFormat":"__auto"}],"title":"CPU Usage","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"overrides":[{"matcher":{"id":"byRegexp","options":"/%/"},"properties":[{"id":"unit","value":"percentunit"}]},{"matcher":{"id":"byName","options":"Namespace"},"properties":[{"id":"links","value":[{"title":"Drill down to pods","url":"/d/490b402361724ab1d4c45666c1fa9b6f/k8s-resources-windows-namespace?${datasource:queryparam}&var-cluster=$cluster&var-namespace=${__data.fields.Namespace}"}]}]}]},"gridPos":{"h":7,"w":24,"x":0,"y":7},"id":2,"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_cpu_cores_request{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(kube_pod_windows_container_resource_cpu_cores_request{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_cpu_cores_limit{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(kube_pod_windows_container_resource_cpu_cores_limit{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true}],"title":"CPU Quota","transformations":[{"id":"joinByField","options":{"byField":"container","mode":"outer"}},{"id":"organize","options":{"excludeByName":{"Time":true,"Time 1":true,"Time 2":true,"Time 3":true,"Time 4":true,"Time 5":true},"indexByName":{"Time 1":0,"Time 2":1,"Time 3":2,"Time 4":3,"Time 5":4,"Value #A":6,"Value #B":7,"Value #C":8,"Value #D":9,"Value #E":10,"container":5},"renameByName":{"Value #A":"CPU Usage","Value #B":"CPU Requests","Value #C":"CPU Requests %","Value #D":"CPU Limits","Value #E":"CPU Limits %","container":"Container"}}}],"type":"table"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"decbytes"}},"gridPos":{"h":7,"w":24,"x":0,"y":14},"id":3,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","legendFormat":"__auto"}],"title":"Memory Usage","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"unit":"bytes"},"overrides":[{"matcher":{"id":"byRegexp","options":"/%/"},"properties":[{"id":"unit","value":"percentunit"}]}]},"gridPos":{"h":7,"w":24,"x":0,"y":21},"id":4,"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_memory_request{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(kube_pod_windows_container_resource_memory_request{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(kube_pod_windows_container_resource_memory_limit{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum(windows_container_private_working_set_usage{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container) / sum(kube_pod_windows_container_resource_memory_limit{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}) by (container)","format":"table","instant":true}],"title":"Memory Quota","transformations":[{"id":"joinByField","options":{"byField":"container","mode":"outer"}},{"id":"organize","options":{"excludeByName":{"Time":true,"Time 1":true,"Time 2":true,"Time 3":true,"Time 4":true,"Time 5":true},"indexByName":{"Time 1":0,"Time 2":1,"Time 3":2,"Time 4":3,"Time 5":4,"Value #A":6,"Value #B":7,"Value #C":8,"Value #D":9,"Value #E":10,"container":5},"renameByName":{"Value #A":"Memory Usage","Value #B":"Memory Requests","Value #C":"Memory Requests %","Value #D":"Memory Limits","Value #E":"Memory Limits %","container":"Container"}}}],"type":"table"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"bytes"}},"gridPos":{"h":7,"w":24,"x":0,"y":28},"id":5,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sort_desc(sum by (container) (rate(windows_container_network_received_bytes_total{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[1m])))","legendFormat":"Received : {{ container }}"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sort_desc(sum by (container) (rate(windows_container_network_transmitted_bytes_total{cluster=\"$cluster\", namespace=\"$namespace\", pod=\"$pod\"}[1m])))","legendFormat":"Transmitted : {{ container }}"}],"title":"Network I/O","type":"timeseries"}],"refresh":"10s","schemaVersion":39,"tags":["kubernetes-mixin"],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"label":"Data source","name":"datasource","query":"prometheus","regex":"","type":"datasource"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":`}}{{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}{{`,"label":"cluster","name":"cluster","query":"label_values(up{job=\"windows-exporter\"}, cluster)","refresh":2,"sort":1,"type":"query","allValue":".*"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":0,"label":"namespace","name":"namespace","query":"label_values(windows_pod_container_available{cluster=\"$cluster\"}, namespace)","refresh":2,"sort":1,"type":"query"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":0,"label":"pod","name":"pod","query":"label_values(windows_pod_container_available{cluster=\"$cluster\",namespace=\"$namespace\"}, pod)","refresh":2,"sort":1,"type":"query"}]},"time":{"from":"now-1h","to":"now"},"timezone": "`}}{{ .Values.grafana.defaultDashboardsTimezone }}{{`","title":"Kubernetes / Compute Resources / Pod(Windows)","uid":"40597a704a610e936dc6ed374a7ce023"}`}} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-workload.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-workload.yaml new file mode 100644 index 0000000000..a1bd68b805 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-workload.yaml @@ -0,0 +1,2024 @@ +{{- /* +Generated from 'k8s-resources-workload' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-workload" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-workload.json: |- + { + "annotations": { + "list": [ + + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 1, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "CPU Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "CPU Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n/sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n/sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(\n container_memory_working_set_bytes{cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Memory Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(\n container_memory_working_set_bytes{cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(\n container_memory_working_set_bytes{cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n/sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(\n container_memory_working_set_bytes{cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n/sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=\"$workload\", workload_type=\"$type\"}\n) by (pod)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Current Receive Bandwidth", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Current Transmit Bandwidth", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Rate of Received Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Received Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "d/6581e46e4e5c7ba40a07646395ef7b23/k8s-resources-pod?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-pod=$__cell", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "(sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Network Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Network Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(avg(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Container Bandwidth by Pod: Received", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(avg(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Container Bandwidth by Pod: Transmitted", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Average Container Bandwidth by Pod", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 11, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 12, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 13, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets Dropped", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(kube_namespace_status_phase{job=\"kube-state-metrics\", cluster=\"$cluster\"}, namespace)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "type", + "options": [ + + ], + "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\"}, workload_type)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "workload", + "options": [ + + ], + "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}, workload)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Compute Resources / Workload", + "uid": "a164a7f0339f99e89cea5cb47e9be617", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-workloads-namespace.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-workloads-namespace.yaml new file mode 100644 index 0000000000..09257b911e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-resources-workloads-namespace.yaml @@ -0,0 +1,2189 @@ +{{- /* +Generated from 'k8s-resources-workloads-namespace' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-resources-workloads-namespace" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-resources-workloads-namespace.json: |- + { + "annotations": { + "list": [ + + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 1, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "quota - requests", + "color": "#F2495C", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + }, + { + "alias": "quota - limits", + "color": "#FF9830", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}} - {{`{{`}}workload_type{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"requests.cpu\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "quota - requests", + "legendLink": null, + "step": 10 + }, + { + "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"limits.cpu\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "quota - limits", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Running Pods", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "CPU Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "CPU Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "d/a164a7f0339f99e89cea5cb47e9be617/k8s-resources-workload?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-workload=$__cell&var-type=$__cell_2", + "pattern": "workload", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Workload Type", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "workload_type", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "count(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload, workload_type)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n/sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(\n node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate{cluster=\"$cluster\", namespace=\"$namespace\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n/sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"cpu\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "quota - requests", + "color": "#F2495C", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + }, + { + "alias": "quota - limits", + "color": "#FF9830", + "dashes": true, + "fill": 0, + "hiddenSeries": true, + "hideTooltip": true, + "legend": true, + "linewidth": 2, + "stack": false + } + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(\n container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}} - {{`{{`}}workload_type{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"requests.memory\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "quota - requests", + "legendLink": null, + "step": 10 + }, + { + "expr": "scalar(kube_resourcequota{cluster=\"$cluster\", namespace=\"$namespace\", type=\"hard\",resource=\"limits.memory\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "quota - limits", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Running Pods", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 0, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Memory Usage", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Requests %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Memory Limits", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "bytes" + }, + { + "alias": "Memory Limits %", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "percentunit" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "d/a164a7f0339f99e89cea5cb47e9be617/k8s-resources-workload?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-workload=$__cell&var-type=$__cell_2", + "pattern": "workload", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Workload Type", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "workload_type", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "count(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload, workload_type)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(\n container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(\n container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n/sum(\n kube_pod_container_resource_requests{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(\n container_memory_working_set_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\", container!=\"\", image!=\"\"}\n * on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n/sum(\n kube_pod_container_resource_limits{job=\"kube-state-metrics\", cluster=\"$cluster\", namespace=\"$namespace\", resource=\"memory\"}\n* on(namespace,pod)\n group_left(workload, workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}\n) by (workload, workload_type)\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Quota", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory Quota", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Current Receive Bandwidth", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Current Transmit Bandwidth", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Rate of Received Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Received Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": false, + "linkTooltip": "Drill down to pods", + "linkUrl": "d/a164a7f0339f99e89cea5cb47e9be617/k8s-resources-workload?var-datasource=$datasource&var-cluster=$cluster&var-namespace=$namespace&var-workload=$__cell&var-type=$type", + "pattern": "workload", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Workload Type", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "workload_type", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "(sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Network Usage", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Network Usage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(avg(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Container Bandwidth by Workload: Received", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(avg(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Container Bandwidth by Workload: Transmitted", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Average Container Bandwidth by Workload", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 11, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 12, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 13, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\", namespace=\"$namespace\"}[$__rate_interval])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": false, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Rate of Packets Dropped", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"kube-state-metrics\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(kube_pod_info{job=\"kube-state-metrics\", cluster=\"$cluster\"}, namespace)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "deployment", + "value": "deployment" + }, + "datasource": "$datasource", + "definition": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\"}, workload_type)", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "type", + "options": [ + + ], + "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\", namespace=\"$namespace\", workload=~\".+\"}, workload_type)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Compute Resources / Namespace (Workloads)", + "uid": "a87fb0d919ec0ea5f6543124e16c42a5", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-windows-cluster-rsrc-use.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-windows-cluster-rsrc-use.yaml new file mode 100644 index 0000000000..0c4a2ca998 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-windows-cluster-rsrc-use.yaml @@ -0,0 +1,24 @@ +{{- /* +Generated from 'k8s-windows-cluster-rsrc-use' from https://github.com/kubernetes-monitoring/kubernetes-mixin.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.windowsMonitoring.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-windows-cluster-rsrc-use" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-windows-cluster-rsrc-use.json: |- + {{`{"editable":`}}{{ .Values.grafana.defaultDashboardsEditable }}{{`,"panels":[{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":24,"x":0,"y":0},"id":1,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_cpu_utilisation:avg1m{cluster=\"$cluster\"} * node:windows_node_num_cpu:sum{cluster=\"$cluster\"} / scalar(sum(node:windows_node_num_cpu:sum{cluster=\"$cluster\"}))","legendFormat":"{{instance}}"}],"title":"CPU Utilisation","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":12,"x":0,"y":7},"id":2,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_memory_utilisation:ratio{cluster=\"$cluster\"}","legendFormat":"{{instance}}"}],"title":"Memory Utilisation","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"short"}},"gridPos":{"h":7,"w":12,"x":12,"y":7},"id":3,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_memory_swap_io_pages:irate{cluster=\"$cluster\"}","legendFormat":"{{instance}}"}],"title":"Memory Saturation (Swap I/O Pages)","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":24,"x":0,"y":14},"id":4,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_disk_utilisation:avg_irate{cluster=\"$cluster\"} / scalar(node:windows_node:sum{cluster=\"$cluster\"})","legendFormat":"{{instance}}"}],"title":"Disk IO Utilisation","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"Bps"}},"gridPos":{"h":7,"w":12,"x":0,"y":21},"id":5,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_net_utilisation:sum_irate{cluster=\"$cluster\"}","legendFormat":"{{instance}}"}],"title":"Net Utilisation (Transmitted)","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"Bps"}},"gridPos":{"h":7,"w":12,"x":12,"y":21},"id":6,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_net_saturation:sum_irate{cluster=\"$cluster\"}","legendFormat":"{{instance}}"}],"title":"Net Utilisation (Dropped)","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":24,"x":0,"y":28},"id":7,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum by (instance)(node:windows_node_filesystem_usage:{cluster=\"$cluster\"})","legendFormat":"{{instance}}"}],"title":"Disk Capacity","type":"timeseries"}],"refresh":"10s","schemaVersion":39,"tags":["kubernetes-mixin"],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"label":"Data source","name":"datasource","query":"prometheus","regex":"","type":"datasource"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":`}}{{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}{{`,"label":"cluster","name":"cluster","query":"label_values(up{job=\"windows-exporter\"}, cluster)","refresh":2,"sort":1,"type":"query","allValue":".*"}]},"time":{"from":"now-1h","to":"now"},"timezone": "`}}{{ .Values.grafana.defaultDashboardsTimezone }}{{`","title":"Kubernetes / USE Method / Cluster(Windows)","uid":"53a43377ec9aaf2ff64dfc7a1f539334"}`}} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-windows-node-rsrc-use.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-windows-node-rsrc-use.yaml new file mode 100644 index 0000000000..890cef3a8d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/k8s-windows-node-rsrc-use.yaml @@ -0,0 +1,24 @@ +{{- /* +Generated from 'k8s-windows-node-rsrc-use' from https://github.com/kubernetes-monitoring/kubernetes-mixin.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.windowsMonitoring.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ template "kube-prometheus-stack-grafana.namespace" . }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "k8s-windows-node-rsrc-use" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + k8s-windows-node-rsrc-use.json: |- + {{`{"editable":`}}{{ .Values.grafana.defaultDashboardsEditable }}{{`,"panels":[{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":12,"x":0,"y":0},"id":1,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_cpu_utilisation:avg1m{cluster=\"$cluster\", instance=\"$instance\"}","legendFormat":"Utilisation"}],"title":"CPU Utilisation","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":12,"x":12,"y":0},"id":2,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"sum by (core) (irate(windows_cpu_time_total{cluster=\"$cluster\", job=\"windows-exporter\", mode!=\"idle\", instance=\"$instance\"}[$__rate_interval]))","legendFormat":"{{core}}"}],"title":"CPU Usage Per Core","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":8,"x":0,"y":7},"id":3,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_memory_utilisation:{cluster=\"$cluster\", instance=\"$instance\"}","legendFormat":"Memory"}],"title":"Memory Utilisation %","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"bytes"}},"gridPos":{"h":7,"w":8,"x":8,"y":7},"id":4,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"max(\n windows_os_visible_memory_bytes{cluster=\"$cluster\", job=\"windows-exporter\", instance=\"$instance\"}\n - windows_memory_available_bytes{cluster=\"$cluster\", job=\"windows-exporter\", instance=\"$instance\"}\n)\n","legendFormat":"memory used"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"max(node:windows_node_memory_totalCached_bytes:sum{cluster=\"$cluster\", instance=\"$instance\"})","legendFormat":"memory cached"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"max(windows_memory_available_bytes{cluster=\"$cluster\", job=\"windows-exporter\", instance=\"$instance\"})","legendFormat":"memory free"}],"title":"Memory Usage","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"short"}},"gridPos":{"h":7,"w":8,"x":16,"y":7},"id":5,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_memory_swap_io_pages:irate{cluster=\"$cluster\", instance=\"$instance\"}","legendFormat":"Swap IO"}],"title":"Memory Saturation (Swap I/O) Pages","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":12,"x":0,"y":14},"id":6,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_disk_utilisation:avg_irate{cluster=\"$cluster\", instance=\"$instance\"}","legendFormat":"Utilisation"}],"title":"Disk IO Utilisation","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"bytes"},"overrides":[{"matcher":{"id":"byRegexp","options":"/io time/"},"properties":[{"id":"unit","value":"ms"}]}]},"gridPos":{"h":7,"w":12,"x":12,"y":14},"id":7,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"max(rate(windows_logical_disk_read_bytes_total{cluster=\"$cluster\", job=\"windows-exporter\", instance=\"$instance\"}[2m]))","legendFormat":"read"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"max(rate(windows_logical_disk_write_bytes_total{cluster=\"$cluster\", job=\"windows-exporter\", instance=\"$instance\"}[2m]))","legendFormat":"written"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"max(rate(windows_logical_disk_read_seconds_total{cluster=\"$cluster\", job=\"windows-exporter\", instance=\"$instance\"}[2m]) + rate(windows_logical_disk_write_seconds_total{cluster=\"$cluster\", job=\"windows-exporter\", instance=\"$instance\"}[2m]))","legendFormat":"io time"}],"title":"Disk IO","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"percentunit"}},"gridPos":{"h":7,"w":24,"x":0,"y":21},"id":8,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_filesystem_usage:{cluster=\"$cluster\", instance=\"$instance\"}","legendFormat":"{{volume}}"}],"title":"Disk Utilisation","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"Bps"}},"gridPos":{"h":7,"w":12,"x":0,"y":28},"id":9,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_net_utilisation:sum_irate{cluster=\"$cluster\", instance=\"$instance\"}","legendFormat":"Utilisation"}],"title":"Net Utilisation (Transmitted)","type":"timeseries"},{"datasource":{"type":"datasource","uid":"-- Mixed --"},"fieldConfig":{"defaults":{"custom":{"fillOpacity":10,"showPoints":"never","spanNulls":true},"unit":"Bps"}},"gridPos":{"h":7,"w":12,"x":12,"y":28},"id":10,"interval":"1m","options":{"legend":{"asTable":true,"calcs":["lastNotNull"],"displayMode":"table","placement":"right","showLegend":true},"tooltip":{"mode":"single"}},"pluginVersion":"v11.0.0","targets":[{"datasource":{"type":"prometheus","uid":"${datasource}"},"expr":"node:windows_node_net_saturation:sum_irate{cluster=\"$cluster\", instance=\"$instance\"}","legendFormat":"Saturation"}],"title":"Net Saturation (Dropped)","type":"timeseries"}],"refresh":"10s","schemaVersion":39,"tags":["kubernetes-mixin"],"templating":{"list":[{"current":{"selected":true,"text":"default","value":"default"},"hide":0,"label":"Data source","name":"datasource","query":"prometheus","regex":"","type":"datasource"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":`}}{{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}{{`,"label":"cluster","name":"cluster","query":"label_values(up{job=\"windows-exporter\"}, cluster)","refresh":2,"sort":1,"type":"query","allValue":".*"},{"datasource":{"type":"prometheus","uid":"${datasource}"},"hide":0,"label":"instance","multi":true,"name":"instance","query":"label_values(windows_system_system_up_time{cluster=\"$cluster\"}, instance)","refresh":2,"type":"query"}]},"time":{"from":"now-1h","to":"now"},"timezone": "`}}{{ .Values.grafana.defaultDashboardsTimezone }}{{`","title":"Kubernetes / USE Method / Node(Windows)","uid":"96e7484b0bb53b74fbc2bcb7723cd40b"}`}} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/kubelet.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/kubelet.yaml new file mode 100644 index 0000000000..bdbf1c2195 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/kubelet.yaml @@ -0,0 +1,2256 @@ +{{- /* +Generated from 'kubelet' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +{{- if (include "exporter.kubelet.enabled" .) }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "kubelet" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + kubelet.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "panels": [ + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "links": [ + + ], + "mappings": [ + + ], + "thresholds": { + "mode": "absolute", + "steps": [ + + ] + }, + "unit": "none" + } + }, + "gridPos": { + "h": 7, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 2, + "links": [ + + ], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7", + "targets": [ + { + "expr": "sum(kubelet_node_name{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "title": "Running Kubelets", + "transparent": false, + "type": "stat" + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "links": [ + + ], + "mappings": [ + + ], + "thresholds": { + "mode": "absolute", + "steps": [ + + ] + }, + "unit": "none" + } + }, + "gridPos": { + "h": 7, + "w": 4, + "x": 4, + "y": 0 + }, + "id": 3, + "links": [ + + ], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7", + "targets": [ + { + "expr": "sum(kubelet_running_pods{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"}) OR sum(kubelet_running_pod_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "title": "Running Pods", + "transparent": false, + "type": "stat" + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "links": [ + + ], + "mappings": [ + + ], + "thresholds": { + "mode": "absolute", + "steps": [ + + ] + }, + "unit": "none" + } + }, + "gridPos": { + "h": 7, + "w": 4, + "x": 8, + "y": 0 + }, + "id": 4, + "links": [ + + ], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7", + "targets": [ + { + "expr": "sum(kubelet_running_containers{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"}) OR sum(kubelet_running_container_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "title": "Running Containers", + "transparent": false, + "type": "stat" + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "links": [ + + ], + "mappings": [ + + ], + "thresholds": { + "mode": "absolute", + "steps": [ + + ] + }, + "unit": "none" + } + }, + "gridPos": { + "h": 7, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 5, + "links": [ + + ], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7", + "targets": [ + { + "expr": "sum(volume_manager_total_volumes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\", state=\"actual_state_of_world\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "title": "Actual Volume Count", + "transparent": false, + "type": "stat" + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "links": [ + + ], + "mappings": [ + + ], + "thresholds": { + "mode": "absolute", + "steps": [ + + ] + }, + "unit": "none" + } + }, + "gridPos": { + "h": 7, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 6, + "links": [ + + ], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7", + "targets": [ + { + "expr": "sum(volume_manager_total_volumes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\",state=\"desired_state_of_world\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "title": "Desired Volume Count", + "transparent": false, + "type": "stat" + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "links": [ + + ], + "mappings": [ + + ], + "thresholds": { + "mode": "absolute", + "steps": [ + + ] + }, + "unit": "none" + } + }, + "gridPos": { + "h": 7, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 7, + "links": [ + + ], + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7", + "targets": [ + { + "expr": "sum(rate(kubelet_node_config_error{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "title": "Config Error Count", + "transparent": false, + "type": "stat" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 8, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(kubelet_runtime_operations_total{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (operation_type, instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_type{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Operation Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 9, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(kubelet_runtime_operations_errors_total{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_type)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_type{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Operation Error Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(kubelet_runtime_operations_duration_seconds_bucket{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_type, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_type{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Operation duration 99th quantile", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(kubelet_pod_start_duration_seconds_count{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} pod", + "refId": "A" + }, + { + "expr": "sum(rate(kubelet_pod_worker_duration_seconds_count{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} worker", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Pod Start Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 12, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(kubelet_pod_start_duration_seconds_bucket{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} pod", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(kubelet_pod_worker_duration_seconds_bucket{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} worker", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Pod Start Duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 28 + }, + "id": 13, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(storage_operation_duration_seconds_count{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_name, volume_plugin)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_name{{`}}`}} {{`{{`}}volume_plugin{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Storage Operation Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 28 + }, + "id": 14, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(storage_operation_errors_total{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_name, volume_plugin)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_name{{`}}`}} {{`{{`}}volume_plugin{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Storage Operation Error Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(storage_operation_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_name, volume_plugin, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_name{{`}}`}} {{`{{`}}volume_plugin{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Storage Operation Duration 99th quantile", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 42 + }, + "id": 16, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(kubelet_cgroup_manager_duration_seconds_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_type)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}operation_type{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Cgroup manager operation rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 42 + }, + "id": 17, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(kubelet_cgroup_manager_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance, operation_type, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}operation_type{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Cgroup manager 99th quantile", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "Pod lifecycle event generator", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 49 + }, + "id": 18, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(kubelet_pleg_relist_duration_seconds_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "PLEG relist rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 49 + }, + "id": 19, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(kubelet_pleg_relist_interval_seconds_bucket{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "PLEG relist interval", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 56 + }, + "id": 20, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(kubelet_pleg_relist_duration_seconds_bucket{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])) by (instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "PLEG relist duration", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 63 + }, + "id": 21, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\",code=~\"2..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "2xx", + "refId": "A" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\",code=~\"3..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "3xx", + "refId": "B" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\",code=~\"4..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "4xx", + "refId": "C" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\",code=~\"5..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "5xx", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "RPC Rate", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 70 + }, + "id": 22, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", instance=~\"$instance\"}[$__rate_interval])) by (instance, verb, url, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Request duration 99th quantile", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 77 + }, + "id": 23, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_resident_memory_bytes{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 77 + }, + "id": 24, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(process_cpu_seconds_total{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 77 + }, + "id": 25, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{cluster=\"$cluster\",job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "rows": [ + + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": "cluster", + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": "instance", + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\",cluster=\"$cluster\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Kubelet", + "uid": "3138fa155d5915769fbded898ac09fd9", + "version": 0 + } +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/namespace-by-pod.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/namespace-by-pod.yaml new file mode 100644 index 0000000000..92882d7dba --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/namespace-by-pod.yaml @@ -0,0 +1,1464 @@ +{{- /* +Generated from 'namespace-by-pod' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "namespace-by-pod" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + namespace-by-pod.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "panels": [ + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "decimals": 0, + "format": "time_series", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 1 + }, + "height": 9, + "id": 3, + "interval": null, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "minSpan": 12, + "nullPointMode": "connected", + "nullText": null, + "options": { + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "max": 10000000000, + "min": 0, + "title": "$namespace", + "unit": "Bps" + }, + "mappings": [ + + ], + "override": { + + }, + "thresholds": [ + { + "color": "dark-green", + "index": 0, + "value": null + }, + { + "color": "dark-yellow", + "index": 1, + "value": 5000000000 + }, + { + "color": "dark-red", + "index": 2, + "value": 7000000000 + } + ], + "values": false + } + }, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 12, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution]))", + "format": "time_series", + "instant": null, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Received", + "type": "gauge", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "decimals": 0, + "format": "time_series", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 1 + }, + "height": 9, + "id": 4, + "interval": null, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "minSpan": 12, + "nullPointMode": "connected", + "nullText": null, + "options": { + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "max": 10000000000, + "min": 0, + "title": "$namespace", + "unit": "Bps" + }, + "mappings": [ + + ], + "override": { + + }, + "thresholds": [ + { + "color": "dark-green", + "index": 0, + "value": null + }, + { + "color": "dark-yellow", + "index": 1, + "value": 5000000000 + }, + { + "color": "dark-red", + "index": 2, + "value": 7000000000 + } + ], + "values": false + } + }, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 12, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution]))", + "format": "time_series", + "instant": null, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Transmitted", + "type": "gauge", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "columns": [ + { + "text": "Time", + "value": "Time" + }, + { + "text": "Value #A", + "value": "Value #A" + }, + { + "text": "Value #B", + "value": "Value #B" + }, + { + "text": "Value #C", + "value": "Value #C" + }, + { + "text": "Value #D", + "value": "Value #D" + }, + { + "text": "Value #E", + "value": "Value #E" + }, + { + "text": "Value #F", + "value": "Value #F" + }, + { + "text": "pod", + "value": "pod" + } + ], + "datasource": "$datasource", + "fill": 1, + "fontSize": "100%", + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 5, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null as zero", + "renderer": "flot", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": false + }, + "spaceLength": 10, + "span": 24, + "styles": [ + { + "alias": "Time", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Time", + "thresholds": [ + + ], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Bandwidth Received", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Bandwidth Transmitted", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Rate of Received Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Received Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Pod", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "Drill down", + "linkUrl": "d/7a18067ce943a40ae25454675c19ff5c/kubernetes-networking-pod?orgId=1&refresh=30s&var-namespace=$namespace&var-pod=$__cell", + "pattern": "pod", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Status", + "type": "table" + }, + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 6, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 7, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 8, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 9, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 30 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 30 + }, + "id": 11, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Packets", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 12, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 13, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 40 + }, + "id": 14, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Errors", + "titleSize": "h6", + "type": "row" + } + ], + "refresh": "10s", + "rows": [ + + ], + "schemaVersion": 18, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".+", + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "kube-system", + "value": "kube-system" + }, + "datasource": "$datasource", + "definition": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "resolution", + "options": [ + { + "selected": false, + "text": "30s", + "value": "30s" + }, + { + "selected": true, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + } + ], + "query": "30s,5m,1h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "interval", + "options": [ + { + "selected": true, + "text": "4h", + "value": "4h" + } + ], + "query": "4h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Networking / Namespace (Pods)", + "uid": "8b7a8b326d7a6f1f04244066368c67af", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/namespace-by-workload.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/namespace-by-workload.yaml new file mode 100644 index 0000000000..5abea97774 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/namespace-by-workload.yaml @@ -0,0 +1,1736 @@ +{{- /* +Generated from 'namespace-by-workload' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "namespace-by-workload" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + namespace-by-workload.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "panels": [ + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 3, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}} workload {{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Received", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}} workload {{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Transmitted", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "columns": [ + { + "text": "Time", + "value": "Time" + }, + { + "text": "Value #A", + "value": "Value #A" + }, + { + "text": "Value #B", + "value": "Value #B" + }, + { + "text": "Value #C", + "value": "Value #C" + }, + { + "text": "Value #D", + "value": "Value #D" + }, + { + "text": "Value #E", + "value": "Value #E" + }, + { + "text": "Value #F", + "value": "Value #F" + }, + { + "text": "Value #G", + "value": "Value #G" + }, + { + "text": "Value #H", + "value": "Value #H" + }, + { + "text": "workload", + "value": "workload" + } + ], + "datasource": "$datasource", + "fill": 1, + "fontSize": "90%", + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 5, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null as zero", + "renderer": "flot", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": false + }, + "spaceLength": 10, + "span": 24, + "styles": [ + { + "alias": "Time", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Time", + "thresholds": [ + + ], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Current Bandwidth Received", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Current Bandwidth Transmitted", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Average Bandwidth Received", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #C", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Average Bandwidth Transmitted", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #D", + "thresholds": [ + + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "Rate of Received Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #E", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #F", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Received Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #G", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Rate of Transmitted Packets Dropped", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #H", + "thresholds": [ + + ], + "type": "number", + "unit": "pps" + }, + { + "alias": "Workload", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTooltip": "Drill down", + "linkUrl": "d/728bf77cc1166d2f3133bf25846876cc/kubernetes-networking-workload?orgId=1&refresh=30s&var-namespace=$namespace&var-type=$type&var-workload=$__cell", + "pattern": "workload", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + }, + { + "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "C", + "step": 10 + }, + { + "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "D", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "E", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "F", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "G", + "step": 10 + }, + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "H", + "step": 10 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Status", + "type": "table" + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 6, + "panels": [ + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 20 + }, + "id": 7, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}} workload {{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Rate of Bytes Received", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 20 + }, + "id": 8, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}} workload {{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Rate of Bytes Transmitted", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Average Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 9, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth HIstory", + "titleSize": "h6", + "type": "row" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 38 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 38 + }, + "id": 11, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 39 + }, + "id": 12, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 40 + }, + "id": 13, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 40 + }, + "id": 14, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Packets", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 15, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 41 + }, + "id": 16, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 41 + }, + "id": 17, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\", workload_type=\"$type\"}) by (workload))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}workload{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Errors", + "titleSize": "h6", + "type": "row" + } + ], + "refresh": "10s", + "rows": [ + + ], + "schemaVersion": 18, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "kube-system", + "value": "kube-system" + }, + "datasource": "$datasource", + "definition": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "deployment", + "value": "deployment" + }, + "datasource": "$datasource", + "definition": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\"}, workload_type)", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "type", + "options": [ + + ], + "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=\"$namespace\", workload=~\".+\"}, workload_type)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "resolution", + "options": [ + { + "selected": false, + "text": "30s", + "value": "30s" + }, + { + "selected": true, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + } + ], + "query": "30s,5m,1h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "interval", + "options": [ + { + "selected": true, + "text": "4h", + "value": "4h" + } + ], + "query": "4h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Networking / Namespace (Workload)", + "uid": "bbb2a765a623ae38130206c7d94a160f", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/node-cluster-rsrc-use.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/node-cluster-rsrc-use.yaml new file mode 100644 index 0000000000..a4bf29fd11 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/node-cluster-rsrc-use.yaml @@ -0,0 +1,1063 @@ +{{- /* +Generated from 'node-cluster-rsrc-use' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled (or .Values.nodeExporter.enabled .Values.nodeExporter.forceDeployDashboards) }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "node-cluster-rsrc-use" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + node-cluster-rsrc-use.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "30s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "((\n instance:node_cpu_utilisation:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}\n *\n instance:node_num_cpu:sum{job=\"node-exporter\", cluster=\"$cluster\"}\n) != 0 )\n/ scalar(sum(instance:node_num_cpu:sum{job=\"node-exporter\", cluster=\"$cluster\"}))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}} instance {{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Utilisation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(\n instance:node_load1_per_cpu:ratio{job=\"node-exporter\", cluster=\"$cluster\"}\n / scalar(count(instance:node_load1_per_cpu:ratio{job=\"node-exporter\", cluster=\"$cluster\"}))\n) != 0\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Saturation (Load1 per CPU)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(\n instance:node_memory_utilisation:ratio{job=\"node-exporter\", cluster=\"$cluster\"}\n / scalar(count(instance:node_memory_utilisation:ratio{job=\"node-exporter\", cluster=\"$cluster\"}))\n) != 0\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Utilisation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 5, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_vmstat_pgmajfault:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Saturation (Major Page Faults)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "rds", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "rds", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + { + "alias": "/Receive/", + "stack": "A" + }, + { + "alias": "/Transmit/", + "stack": "B", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_network_receive_bytes_excluding_lo:rate5m{job=\"node-exporter\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Receive", + "refId": "A" + }, + { + "expr": "instance:node_network_transmit_bytes_excluding_lo:rate5m{job=\"node-exporter\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Transmit", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Utilisation (Bytes Receive/Transmit)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 7, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + { + "alias": "/ Receive/", + "stack": "A" + }, + { + "alias": "/ Transmit/", + "stack": "B", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_network_receive_drop_excluding_lo:rate5m{job=\"node-exporter\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Receive", + "refId": "A" + }, + { + "expr": "instance:node_network_transmit_drop_excluding_lo:rate5m{job=\"node-exporter\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} Transmit", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Saturation (Drops Receive/Transmit)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Network", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(\n instance_device:node_disk_io_time_seconds:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}\n / scalar(count(instance_device:node_disk_io_time_seconds:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}))\n) != 0\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Disk IO Utilisation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(\n instance_device:node_disk_io_time_weighted_seconds:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}\n / scalar(count(instance_device:node_disk_io_time_weighted_seconds:rate5m{job=\"node-exporter\", cluster=\"$cluster\"}))\n) != 0\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}} {{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Disk IO Saturation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Disk IO", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum without (device) (\n max without (fstype, mountpoint) ((\n node_filesystem_size_bytes{job=\"node-exporter\", fstype!=\"\", mountpoint!=\"\", cluster=\"$cluster\"}\n -\n node_filesystem_avail_bytes{job=\"node-exporter\", fstype!=\"\", mountpoint!=\"\", cluster=\"$cluster\"}\n ) != 0)\n)\n/ scalar(sum(max without (fstype, mountpoint) (node_filesystem_size_bytes{job=\"node-exporter\", fstype!=\"\", mountpoint!=\"\", cluster=\"$cluster\"})))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Disk Space Utilisation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Disk Space", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "node-exporter-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(node_time_seconds, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Node Exporter / USE Method / Cluster", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/node-rsrc-use.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/node-rsrc-use.yaml new file mode 100644 index 0000000000..9c1a8fe59f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/node-rsrc-use.yaml @@ -0,0 +1,1089 @@ +{{- /* +Generated from 'node-rsrc-use' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled (or .Values.nodeExporter.enabled .Values.nodeExporter.forceDeployDashboards) }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "node-rsrc-use" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + node-rsrc-use.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "30s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_cpu_utilisation:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Utilisation", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Utilisation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_load1_per_cpu:ratio{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Saturation", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Saturation (Load1 per CPU)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_memory_utilisation:ratio{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Utilisation", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Utilisation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 5, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_vmstat_pgmajfault:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Major page Faults", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Saturation (Major Page Faults)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "rds", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "rds", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + { + "alias": "/Receive/", + "stack": "A" + }, + { + "alias": "/Transmit/", + "stack": "B", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_network_receive_bytes_excluding_lo:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Receive", + "refId": "A" + }, + { + "expr": "instance:node_network_transmit_bytes_excluding_lo:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Transmit", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Utilisation (Bytes Receive/Transmit)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 7, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + { + "alias": "/ Receive/", + "stack": "A" + }, + { + "alias": "/ Transmit/", + "stack": "B", + "transform": "negative-Y" + } + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance:node_network_receive_drop_excluding_lo:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Receive", + "refId": "A" + }, + { + "expr": "instance:node_network_transmit_drop_excluding_lo:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Transmit", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Saturation (Drops Receive/Transmit)", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Network", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance_device:node_disk_io_time_seconds:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Disk IO Utilisation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "instance_device:node_disk_io_time_weighted_seconds:rate5m{job=\"node-exporter\", instance=\"$instance\", cluster=\"$cluster\"} != 0", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Disk IO Saturation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Disk IO", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "fillGradient": 0, + "gridPos": { + + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(1 -\n (\n max without (mountpoint, fstype) (node_filesystem_avail_bytes{job=\"node-exporter\", fstype!=\"\", instance=\"$instance\", cluster=\"$cluster\"})\n /\n max without (mountpoint, fstype) (node_filesystem_size_bytes{job=\"node-exporter\", fstype!=\"\", instance=\"$instance\", cluster=\"$cluster\"})\n ) != 0\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Disk Space Utilisation", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Disk Space", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "node-exporter-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(node_time_seconds, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(node_exporter_build_info{job=\"node-exporter\", cluster=\"$cluster\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Node Exporter / USE Method / Node", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/nodes-darwin.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/nodes-darwin.yaml new file mode 100644 index 0000000000..562802fa07 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/nodes-darwin.yaml @@ -0,0 +1,1073 @@ +{{- /* +Generated from 'nodes-darwin' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled (and (or .Values.nodeExporter.enabled .Values.nodeExporter.forceDeployDashboards) .Values.nodeExporter.operatingSystems.darwin.enabled) }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "nodes-darwin" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + nodes-darwin.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "30s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(\n (1 - sum without (mode) (rate(node_cpu_seconds_total{job=\"node-exporter\", mode=~\"idle|iowait|steal\", instance=\"$instance\"}[$__rate_interval])))\n/ ignoring(cpu) group_left\n count without (cpu, mode) (node_cpu_seconds_total{job=\"node-exporter\", mode=\"idle\", instance=\"$instance\"})\n)\n", + "format": "time_series", + "intervalFactor": 5, + "legendFormat": "{{`{{`}}cpu{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": 0, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 0, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "node_load1{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "1m load average", + "refId": "A" + }, + { + "expr": "node_load5{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "5m load average", + "refId": "B" + }, + { + "expr": "node_load15{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "15m load average", + "refId": "C" + }, + { + "expr": "count(node_cpu_seconds_total{job=\"node-exporter\", instance=\"$instance\", mode=\"idle\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "logical cores", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Load Average", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 9, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "node_memory_total_bytes{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Physical Memory", + "refId": "A" + }, + { + "expr": "(\n node_memory_internal_bytes{job=\"node-exporter\", instance=\"$instance\"} -\n node_memory_purgeable_bytes{job=\"node-exporter\", instance=\"$instance\"} +\n node_memory_wired_bytes{job=\"node-exporter\", instance=\"$instance\"} +\n node_memory_compressed_bytes{job=\"node-exporter\", instance=\"$instance\"}\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Memory Used", + "refId": "B" + }, + { + "expr": "(\n node_memory_internal_bytes{job=\"node-exporter\", instance=\"$instance\"} -\n node_memory_purgeable_bytes{job=\"node-exporter\", instance=\"$instance\"}\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "App Memory", + "refId": "C" + }, + { + "expr": "node_memory_wired_bytes{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Wired Memory", + "refId": "D" + }, + { + "expr": "node_memory_compressed_bytes{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Compressed", + "refId": "E" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)" + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + } + }, + "gridPos": { + + }, + "id": 5, + "span": 3, + "targets": [ + { + "expr": "(\n (\n avg(node_memory_internal_bytes{job=\"node-exporter\", instance=\"$instance\"}) -\n avg(node_memory_purgeable_bytes{job=\"node-exporter\", instance=\"$instance\"}) +\n avg(node_memory_wired_bytes{job=\"node-exporter\", instance=\"$instance\"}) +\n avg(node_memory_compressed_bytes{job=\"node-exporter\", instance=\"$instance\"})\n ) /\n avg(node_memory_total_bytes{job=\"node-exporter\", instance=\"$instance\"})\n)\n*\n100\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "" + } + ], + "title": "Memory Usage", + "transparent": false, + "type": "gauge" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 0, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + { + "alias": "/ read| written/", + "yaxis": 1 + }, + { + "alias": "/ io time/", + "yaxis": 2 + } + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(node_disk_read_bytes_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}} read", + "refId": "A" + }, + { + "expr": "rate(node_disk_written_bytes_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}} written", + "refId": "B" + }, + { + "expr": "rate(node_disk_io_time_seconds_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}} io time", + "refId": "C" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": { + + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Mounted on" + }, + "properties": [ + { + "id": "custom.width", + "value": 260 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Size" + }, + "properties": [ + { + "id": "custom.width", + "value": 93 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "custom.width", + "value": 72 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "custom.width", + "value": 88 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used, %" + }, + "properties": [ + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.displayMode", + "value": "gradient-gauge" + }, + { + "id": "max", + "value": 1 + }, + { + "id": "min", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + + }, + "id": 7, + "span": 6, + "targets": [ + { + "expr": "max by (mountpoint) (node_filesystem_size_bytes{job=\"node-exporter\", instance=\"$instance\", fstype!=\"\", mountpoint!=\"\"})\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "" + }, + { + "expr": "max by (mountpoint) (node_filesystem_avail_bytes{job=\"node-exporter\", instance=\"$instance\", fstype!=\"\", mountpoint!=\"\"})\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "" + } + ], + "title": "Disk Space Usage", + "transformations": [ + { + "id": "groupBy", + "options": { + "fields": { + "Value #A": { + "aggregations": [ + "lastNotNull" + ], + "operation": "aggregate" + }, + "Value #B": { + "aggregations": [ + "lastNotNull" + ], + "operation": "aggregate" + }, + "mountpoint": { + "aggregations": [ + + ], + "operation": "groupby" + } + } + } + }, + { + "id": "merge", + "options": { + + } + }, + { + "id": "calculateField", + "options": { + "alias": "Used", + "binary": { + "left": "Value #A (lastNotNull)", + "operator": "-", + "reducer": "sum", + "right": "Value #B (lastNotNull)" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Used, %", + "binary": { + "left": "Used", + "operator": "/", + "reducer": "sum", + "right": "Value #A (lastNotNull)" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + + }, + "indexByName": { + + }, + "renameByName": { + "Value #A (lastNotNull)": "Size", + "Value #B (lastNotNull)": "Available", + "mountpoint": "Mounted on" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": { + + }, + "sort": [ + { + "field": "Mounted on" + } + ] + } + } + ], + "transparent": false, + "type": "table" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Disk", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "Network received (bits/s)", + "fill": 0, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(node_network_receive_bytes_total{job=\"node-exporter\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Received", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "Network transmitted (bits/s)", + "fill": 0, + "fillGradient": 0, + "gridPos": { + + }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(node_network_transmit_bytes_total{job=\"node-exporter\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Transmitted", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Network", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "node-exporter-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": "Instance", + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(node_uname_info{job=\"node-exporter\", sysname=\"Darwin\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Node Exporter / MacOS", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/nodes.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/nodes.yaml new file mode 100644 index 0000000000..08e567b2f5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/nodes.yaml @@ -0,0 +1,1066 @@ +{{- /* +Generated from 'nodes' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled (and (or .Values.nodeExporter.enabled .Values.nodeExporter.forceDeployDashboards) .Values.nodeExporter.operatingSystems.linux.enabled) }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "nodes" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + nodes.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "30s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(\n (1 - sum without (mode) (rate(node_cpu_seconds_total{job=\"node-exporter\", mode=~\"idle|iowait|steal\", instance=\"$instance\"}[$__rate_interval])))\n/ ignoring(cpu) group_left\n count without (cpu, mode) (node_cpu_seconds_total{job=\"node-exporter\", mode=\"idle\", instance=\"$instance\"})\n)\n", + "format": "time_series", + "intervalFactor": 5, + "legendFormat": "{{`{{`}}cpu{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": 0, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": 1, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 0, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "node_load1{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "1m load average", + "refId": "A" + }, + { + "expr": "node_load5{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "5m load average", + "refId": "B" + }, + { + "expr": "node_load15{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "15m load average", + "refId": "C" + }, + { + "expr": "count(node_cpu_seconds_total{job=\"node-exporter\", instance=\"$instance\", mode=\"idle\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "logical cores", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Load Average", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "CPU", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 9, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(\n node_memory_MemTotal_bytes{job=\"node-exporter\", instance=\"$instance\"}\n-\n node_memory_MemFree_bytes{job=\"node-exporter\", instance=\"$instance\"}\n-\n node_memory_Buffers_bytes{job=\"node-exporter\", instance=\"$instance\"}\n-\n node_memory_Cached_bytes{job=\"node-exporter\", instance=\"$instance\"}\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "memory used", + "refId": "A" + }, + { + "expr": "node_memory_Buffers_bytes{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "memory buffers", + "refId": "B" + }, + { + "expr": "node_memory_Cached_bytes{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "memory cached", + "refId": "C" + }, + { + "expr": "node_memory_MemFree_bytes{job=\"node-exporter\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "memory free", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)" + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 80 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 90 + } + ] + }, + "unit": "percent" + } + }, + "gridPos": { + + }, + "id": 5, + "span": 3, + "targets": [ + { + "expr": "100 -\n(\n avg(node_memory_MemAvailable_bytes{job=\"node-exporter\", instance=\"$instance\"}) /\n avg(node_memory_MemTotal_bytes{job=\"node-exporter\", instance=\"$instance\"})\n* 100\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "" + } + ], + "title": "Memory Usage", + "transparent": false, + "type": "gauge" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Memory", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 0, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + { + "alias": "/ read| written/", + "yaxis": 1 + }, + { + "alias": "/ io time/", + "yaxis": 2 + } + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(node_disk_read_bytes_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}} read", + "refId": "A" + }, + { + "expr": "rate(node_disk_written_bytes_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}} written", + "refId": "B" + }, + { + "expr": "rate(node_disk_io_time_seconds_total{job=\"node-exporter\", instance=\"$instance\", device=~\"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}} io time", + "refId": "C" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Disk I/O", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "percentunit", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "datasource": "$datasource", + "fieldConfig": { + "defaults": { + "custom": { + + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "yellow", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "decbytes" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Mounted on" + }, + "properties": [ + { + "id": "custom.width", + "value": 260 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Size" + }, + "properties": [ + { + "id": "custom.width", + "value": 93 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used" + }, + "properties": [ + { + "id": "custom.width", + "value": 72 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Available" + }, + "properties": [ + { + "id": "custom.width", + "value": 88 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Used, %" + }, + "properties": [ + { + "id": "unit", + "value": "percentunit" + }, + { + "id": "custom.displayMode", + "value": "gradient-gauge" + }, + { + "id": "max", + "value": 1 + }, + { + "id": "min", + "value": 0 + } + ] + } + ] + }, + "gridPos": { + + }, + "id": 7, + "span": 6, + "targets": [ + { + "expr": "max by (mountpoint) (node_filesystem_size_bytes{job=\"node-exporter\", instance=\"$instance\", fstype!=\"\", mountpoint!=\"\"})\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "" + }, + { + "expr": "max by (mountpoint) (node_filesystem_avail_bytes{job=\"node-exporter\", instance=\"$instance\", fstype!=\"\", mountpoint!=\"\"})\n", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "" + } + ], + "title": "Disk Space Usage", + "transformations": [ + { + "id": "groupBy", + "options": { + "fields": { + "Value #A": { + "aggregations": [ + "lastNotNull" + ], + "operation": "aggregate" + }, + "Value #B": { + "aggregations": [ + "lastNotNull" + ], + "operation": "aggregate" + }, + "mountpoint": { + "aggregations": [ + + ], + "operation": "groupby" + } + } + } + }, + { + "id": "merge", + "options": { + + } + }, + { + "id": "calculateField", + "options": { + "alias": "Used", + "binary": { + "left": "Value #A (lastNotNull)", + "operator": "-", + "reducer": "sum", + "right": "Value #B (lastNotNull)" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "calculateField", + "options": { + "alias": "Used, %", + "binary": { + "left": "Used", + "operator": "/", + "reducer": "sum", + "right": "Value #A (lastNotNull)" + }, + "mode": "binary", + "reduce": { + "reducer": "sum" + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": { + + }, + "indexByName": { + + }, + "renameByName": { + "Value #A (lastNotNull)": "Size", + "Value #B (lastNotNull)": "Available", + "mountpoint": "Mounted on" + } + } + }, + { + "id": "sortBy", + "options": { + "fields": { + + }, + "sort": [ + { + "field": "Mounted on" + } + ] + } + } + ], + "transparent": false, + "type": "table" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Disk", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "Network received (bits/s)", + "fill": 0, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(node_network_receive_bytes_total{job=\"node-exporter\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Received", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "description": "Network transmitted (bits/s)", + "fill": 0, + "fillGradient": 0, + "gridPos": { + + }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(node_network_transmit_bytes_total{job=\"node-exporter\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}device{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Transmitted", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Network", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "node-exporter-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": "Instance", + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(node_uname_info{job=\"node-exporter\", sysname!=\"Darwin\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Node Exporter / Nodes", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/persistentvolumesusage.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/persistentvolumesusage.yaml new file mode 100644 index 0000000000..0e12e0a7bb --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/persistentvolumesusage.yaml @@ -0,0 +1,587 @@ +{{- /* +Generated from 'persistentvolumesusage' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "persistentvolumesusage" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + persistentvolumesusage.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 9, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "(\n sum without(instance, node) (topk(1, (kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n -\n sum without(instance, node) (topk(1, (kubelet_volume_stats_available_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n)\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Used Space", + "refId": "A" + }, + { + "expr": "sum without(instance, node) (topk(1, (kubelet_volume_stats_available_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Free Space", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Volume Space Usage", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "$datasource", + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + + }, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "rightSide": true + }, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "max without(instance,node) (\n(\n topk(1, kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n -\n topk(1, kubelet_volume_stats_available_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n)\n/\ntopk(1, kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n* 100)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "80, 90", + "title": "Volume Space Usage", + "tooltip": { + "shared": false + }, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 9, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes_used{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Used inodes", + "refId": "A" + }, + { + "expr": "(\n sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n -\n sum without(instance, node) (topk(1, (kubelet_volume_stats_inodes_used{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})))\n)\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": " Free inodes", + "refId": "B" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Volume inodes Usage", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "rgba(50, 172, 45, 0.97)", + "rgba(237, 129, 40, 0.89)", + "rgba(245, 54, 54, 0.9)" + ], + "datasource": "$datasource", + "format": "percent", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + + }, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "rightSide": true + }, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 3, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "max without(instance,node) (\ntopk(1, kubelet_volume_stats_inodes_used{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n/\ntopk(1, kubelet_volume_stats_inodes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\", persistentvolumeclaim=\"$volume\"})\n* 100)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "80, 90", + "title": "Volume inodes Usage", + "tooltip": { + "shared": false + }, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": "cluster", + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(kubelet_volume_stats_capacity_bytes{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\"}, namespace)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": "PersistentVolumeClaim", + "multi": false, + "name": "volume", + "options": [ + + ], + "query": "label_values(kubelet_volume_stats_capacity_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics\", namespace=\"$namespace\"}, persistentvolumeclaim)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-7d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Persistent Volumes", + "uid": "919b92a8e8041bd567af9edab12c840c", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/pod-total.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/pod-total.yaml new file mode 100644 index 0000000000..b174822a5a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/pod-total.yaml @@ -0,0 +1,1228 @@ +{{- /* +Generated from 'pod-total' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "pod-total" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + pod-total.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "panels": [ + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "decimals": 0, + "format": "time_series", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 1 + }, + "height": 9, + "id": 3, + "interval": null, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "minSpan": 12, + "nullPointMode": "connected", + "nullText": null, + "options": { + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "max": 10000000000, + "min": 0, + "title": "$namespace: $pod", + "unit": "Bps" + }, + "mappings": [ + + ], + "override": { + + }, + "thresholds": [ + { + "color": "dark-green", + "index": 0, + "value": null + }, + { + "color": "dark-yellow", + "index": 1, + "value": 5000000000 + }, + { + "color": "dark-red", + "index": 2, + "value": 7000000000 + } + ], + "values": false + } + }, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 12, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution]))", + "format": "time_series", + "instant": null, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Received", + "type": "gauge", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "decimals": 0, + "format": "time_series", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 1 + }, + "height": 9, + "id": 4, + "interval": null, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "minSpan": 12, + "nullPointMode": "connected", + "nullText": null, + "options": { + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "max": 10000000000, + "min": 0, + "title": "$namespace: $pod", + "unit": "Bps" + }, + "mappings": [ + + ], + "override": { + + }, + "thresholds": [ + { + "color": "dark-green", + "index": 0, + "value": null + }, + { + "color": "dark-yellow", + "index": 1, + "value": 5000000000 + }, + { + "color": "dark-red", + "index": 2, + "value": 7000000000 + } + ], + "values": false + } + }, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 12, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution]))", + "format": "time_series", + "instant": null, + "intervalFactor": 1, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Transmitted", + "type": "gauge", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "current" + }, + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 5, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 6, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_bytes_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 8, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Packets", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 11, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 32 + }, + "id": 12, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_receive_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 32 + }, + "id": 13, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(container_network_transmit_packets_dropped_total{cluster=\"$cluster\",namespace=~\"$namespace\", pod=~\"$pod\"}[$interval:$resolution])) by (pod)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Errors", + "titleSize": "h6", + "type": "row" + } + ], + "refresh": "10s", + "rows": [ + + ], + "schemaVersion": 18, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".+", + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "kube-system", + "value": "kube-system" + }, + "datasource": "$datasource", + "definition": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(container_network_receive_packets_total{cluster=\"$cluster\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".+", + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "definition": "label_values(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}, pod)", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "pod", + "options": [ + + ], + "query": "label_values(container_network_receive_packets_total{cluster=\"$cluster\",namespace=~\"$namespace\"}, pod)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "resolution", + "options": [ + { + "selected": false, + "text": "30s", + "value": "30s" + }, + { + "selected": true, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + } + ], + "query": "30s,5m,1h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "interval", + "options": [ + { + "selected": true, + "text": "4h", + "value": "4h" + } + ], + "query": "4h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Networking / Pod", + "uid": "7a18067ce943a40ae25454675c19ff5c", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/prometheus-remote-write.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/prometheus-remote-write.yaml new file mode 100644 index 0000000000..5fc57e1b28 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/prometheus-remote-write.yaml @@ -0,0 +1,1674 @@ +{{- /* +Generated from 'prometheus-remote-write' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled .Values.prometheus.prometheusSpec.remoteWriteDashboards }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "prometheus-remote-write" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + prometheus-remote-write.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "60s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "(\n prometheus_remote_storage_highest_timestamp_in_seconds{cluster=~\"$cluster\", instance=~\"$instance\"} \n- \n ignoring(remote_name, url) group_right(instance) (prometheus_remote_storage_queue_highest_sent_timestamp_seconds{cluster=~\"$cluster\", instance=~\"$instance\"} != 0)\n)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Highest Timestamp In vs. Highest Timestamp Sent", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "clamp_min(\n rate(prometheus_remote_storage_highest_timestamp_in_seconds{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) \n- \n ignoring (remote_name, url) group_right(instance) rate(prometheus_remote_storage_queue_highest_sent_timestamp_seconds{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])\n, 0)\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate[5m]", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Timestamps", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(\n prometheus_remote_storage_samples_in_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])\n- \n ignoring(remote_name, url) group_right(instance) (rate(prometheus_remote_storage_succeeded_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]))\n- \n (rate(prometheus_remote_storage_dropped_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_dropped_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]))\n", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate, in vs. succeeded or dropped [5m]", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Samples", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 5, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "minSpan": 6, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_remote_storage_shards{cluster=~\"$cluster\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Shards", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_remote_storage_shards_max{cluster=~\"$cluster\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Max Shards", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 7, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_remote_storage_shards_min{cluster=~\"$cluster\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Min Shards", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_remote_storage_shards_desired{cluster=~\"$cluster\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Desired Shards", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Shards", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_remote_storage_shard_capacity{cluster=~\"$cluster\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Shard Capacity", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_remote_storage_pending_samples{cluster=~\"$cluster\", instance=~\"$instance\"} or prometheus_remote_storage_samples_pending{cluster=~\"$cluster\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Pending Samples", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Shard Details", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 11, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_wal_segment_current{cluster=~\"$cluster\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "TSDB Current Segment", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 12, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_wal_watcher_current_segment{cluster=~\"$cluster\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}consumer{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Remote Write Current Segment", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Segments", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 13, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_remote_storage_dropped_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_dropped_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Dropped Samples", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 14, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_remote_storage_failed_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_failed_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Failed Samples", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 15, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_remote_storage_retried_samples_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m]) or rate(prometheus_remote_storage_samples_retried_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Retried Samples", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 16, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 3, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_remote_storage_enqueue_retries_total{cluster=~\"$cluster\", instance=~\"$instance\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}}:{{`{{`}}instance{{`}}`}} {{`{{`}}remote_name{{`}}`}}:{{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Enqueue Retries", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Misc. Rates", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "prometheus-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + "text": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "value": { + "selected": true, + "text": "All", + "value": "$__all" + } + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": true, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(kube_pod_container_info{image=~\".*prometheus.*\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + "text": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "value": { + "selected": true, + "text": "All", + "value": "$__all" + } + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(prometheus_build_info{cluster=~\"$cluster\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "url", + "options": [ + + ], + "query": "label_values(prometheus_remote_storage_shards{cluster=~\"$cluster\", instance=~\"$instance\"}, url)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Prometheus / Remote Write", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/prometheus.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/prometheus.yaml new file mode 100644 index 0000000000..b1f9d73332 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/prometheus.yaml @@ -0,0 +1,1235 @@ +{{- /* +Generated from 'prometheus' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "prometheus" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + prometheus.json: |- + { + "annotations": { + "list": [ + + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "links": [ + + ], + "refresh": "60s", + "rows": [ + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "styles": [ + { + "alias": "Time", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "hidden" + }, + { + "alias": "Count", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #A", + "thresholds": [ + + ], + "type": "hidden", + "unit": "short" + }, + { + "alias": "Uptime", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "Value #B", + "thresholds": [ + + ], + "type": "number", + "unit": "s" + }, + { + "alias": "Instance", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "instance", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Job", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "job", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "Version", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": false, + "linkTargetBlank": false, + "linkTooltip": "Drill down", + "linkUrl": "", + "pattern": "version", + "thresholds": [ + + ], + "type": "number", + "unit": "short" + }, + { + "alias": "", + "colorMode": null, + "colors": [ + + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + + ], + "type": "string", + "unit": "short" + } + ], + "targets": [ + { + "expr": "count by (job, instance, version) (prometheus_build_info{job=~\"$job\", instance=~\"$instance\"})", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "A", + "step": 10 + }, + { + "expr": "max by (job, instance) (time() - process_start_time_seconds{job=~\"$job\", instance=~\"$instance\"})", + "format": "table", + "instant": true, + "intervalFactor": 2, + "legendFormat": "", + "refId": "B", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Prometheus Stats", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "transform": "table", + "type": "table", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Prometheus Stats", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(prometheus_target_sync_length_seconds_sum{job=~\"$job\",instance=~\"$instance\"}[5m])) by (scrape_job) * 1e3", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}scrape_job{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Target Sync", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 3, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(prometheus_sd_discovered_targets{job=~\"$job\",instance=~\"$instance\"})", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "Targets", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Targets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Discovery", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_target_interval_length_seconds_sum{job=~\"$job\",instance=~\"$instance\"}[5m]) / rate(prometheus_target_interval_length_seconds_count{job=~\"$job\",instance=~\"$instance\"}[5m]) * 1e3", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}interval{{`}}`}} configured", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Scrape Interval Duration", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (job) (rate(prometheus_target_scrapes_exceeded_body_size_limit_total[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "exceeded body size limit: {{`{{`}}job{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum by (job) (rate(prometheus_target_scrapes_exceeded_sample_limit_total[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "exceeded sample limit: {{`{{`}}job{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum by (job) (rate(prometheus_target_scrapes_sample_duplicate_timestamp_total[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "duplicate timestamp: {{`{{`}}job{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum by (job) (rate(prometheus_target_scrapes_sample_out_of_bounds_total[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "out of bounds: {{`{{`}}job{{`}}`}}", + "legendLink": null, + "step": 10 + }, + { + "expr": "sum by (job) (rate(prometheus_target_scrapes_sample_out_of_order_total[1m]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "out of order: {{`{{`}}job{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Scrape failures", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_tsdb_head_samples_appended_total{job=~\"$job\",instance=~\"$instance\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}job{{`}}`}} {{`{{`}}instance{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Appended Samples", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Retrieval", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 7, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_head_series{job=~\"$job\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}job{{`}}`}} {{`{{`}}instance{{`}}`}} head series", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Head Series", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "prometheus_tsdb_head_chunks{job=~\"$job\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}job{{`}}`}} {{`{{`}}instance{{`}}`}} head chunks", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Head Chunks", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Storage", + "titleSize": "h6" + }, + { + "collapse": false, + "height": "250px", + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 9, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "rate(prometheus_engine_query_duration_seconds_count{job=~\"$job\",instance=~\"$instance\",slice=\"inner_eval\"}[5m])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}job{{`}}`}} {{`{{`}}instance{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Query Rate", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 10, + "id": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "links": [ + + ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "max by (slice) (prometheus_engine_query_duration_seconds{quantile=\"0.9\",job=~\"$job\",instance=~\"$instance\"}) * 1e3", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}slice{{`}}`}}", + "legendLink": null, + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Stage Duration", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Query", + "titleSize": "h6" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "prometheus-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".+", + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": "job", + "multi": true, + "name": "job", + "options": [ + + ], + "query": "label_values(prometheus_build_info{job=\"prometheus-k8s\",namespace=\"monitoring\"}, job)", + "refresh": 1, + "regex": "", + "sort": 2, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".+", + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": "instance", + "multi": true, + "name": "instance", + "options": [ + + ], + "query": "label_values(prometheus_build_info{job=~\"$job\"}, instance)", + "refresh": 1, + "regex": "", + "sort": 2, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Prometheus / Overview", + "uid": "", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/proxy.yaml new file mode 100644 index 0000000000..69b8abcd60 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/proxy.yaml @@ -0,0 +1,1276 @@ +{{- /* +Generated from 'proxy' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +{{- if (include "exporter.kubeProxy.enabled" .)}} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "proxy" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + proxy.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + + }, + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "rightSide": true + }, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + {{- if .Values.k3sServer.enabled }} + "expr": "sum(up{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", metrics_path=\"/metrics\"})", + {{- else }} + "expr": "sum(up{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\"})", + {{- end }} + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Up", + "tooltip": { + "shared": false + }, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "min" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 5, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(kubeproxy_sync_proxy_rules_duration_seconds_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "rate", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rules Sync Rate", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 5, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99,rate(kubeproxy_sync_proxy_rules_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rule Sync Latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(kubeproxy_network_programming_duration_seconds_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "rate", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Programming Rate", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 6, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(kubeproxy_network_programming_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])) by (instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Network Programming Latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\",code=~\"2..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "2xx", + "refId": "A" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\",code=~\"3..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "3xx", + "refId": "B" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\",code=~\"4..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "4xx", + "refId": "C" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\",code=~\"5..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "5xx", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Kube API Request Rate", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 8, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\",instance=~\"$instance\",verb=\"POST\"}[$__rate_interval])) by (verb, url, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Post Request Latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\", instance=~\"$instance\", verb=\"GET\"}[$__rate_interval])) by (verb, url, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Get Request Latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_resident_memory_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 11, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(process_cpu_seconds_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\",instance=~\"$instance\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU usage", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 12, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": "cluster", + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubeProxy.jobName" . }}\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubeProxy.jobName" . }}\", cluster=\"$cluster\", job=\"{{ include "exporter.kubeProxy.jobName" . }}\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Proxy", + "uid": "632e265de029684c40b21cb76bca4f94", + "version": 0 + } +{{- end }}{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/scheduler.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/scheduler.yaml new file mode 100644 index 0000000000..4d439c8980 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/scheduler.yaml @@ -0,0 +1,1118 @@ +{{- /* +Generated from 'scheduler' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +{{- if (include "exporter.kubeScheduler.enabled" .)}} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "scheduler" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + scheduler.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + + ] + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "refresh": "10s", + "rows": [ + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": "$datasource", + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + + }, + "id": 2, + "interval": "1m", + "legend": { + "alignAsTable": true, + "rightSide": true + }, + "links": [ + + ], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "span": 2, + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "targets": [ + { + {{- if .Values.k3sServer.enabled }} + "expr": "sum(up{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", metrics_path=\"/metrics\"})", + {{- else }} + "expr": "sum(up{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\"})", + {{- end }} + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "", + "refId": "A" + } + ], + "thresholds": "", + "title": "Up", + "tooltip": { + "shared": false + }, + "type": "singlestat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "min" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 3, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 5, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(scheduler_e2e_scheduling_duration_seconds_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} e2e", + "refId": "A" + }, + { + "expr": "sum(rate(scheduler_binding_duration_seconds_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} binding", + "refId": "B" + }, + { + "expr": "sum(rate(scheduler_scheduling_algorithm_duration_seconds_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} scheduling algorithm", + "refId": "C" + }, + { + "expr": "sum(rate(scheduler_volume_scheduling_duration_seconds_count{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance)", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} volume", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Scheduling Rate", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 4, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 5, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(scheduler_e2e_scheduling_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\",instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} e2e", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(scheduler_binding_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\",instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} binding", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(scheduler_scheduling_algorithm_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\",instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} scheduling algorithm", + "refId": "C" + }, + { + "expr": "histogram_quantile(0.99, sum(rate(scheduler_volume_scheduling_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\",instance=~\"$instance\"}[$__rate_interval])) by (cluster, instance, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}cluster{{`}}`}} {{`{{`}}instance{{`}}`}} volume", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Scheduling latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 5, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\",code=~\"2..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "2xx", + "refId": "A" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\",code=~\"3..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "3xx", + "refId": "B" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\",code=~\"4..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "4xx", + "refId": "C" + }, + { + "expr": "sum(rate(rest_client_requests_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\",code=~\"5..\"}[$__rate_interval]))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "5xx", + "refId": "D" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Kube API Request Rate", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 6, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 8, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\", verb=\"POST\"}[$__rate_interval])) by (verb, url, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Post Request Latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 7, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "histogram_quantile(0.99, sum(rate(rest_client_request_duration_seconds_bucket{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\", verb=\"GET\"}[$__rate_interval])) by (verb, url, le))", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}verb{{`}}`}} {{`{{`}}url{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Get Request Latency 99th Quantile", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "s", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 8, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "process_resident_memory_bytes{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Memory", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 9, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "rate(process_cpu_seconds_total{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", instance=~\"$instance\"}[$__rate_interval])", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "CPU usage", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "fillGradient": 0, + "gridPos": { + + }, + "id": 10, + "interval": "1m", + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ + + ], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 4, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "go_goroutines{cluster=\"$cluster\", job=\"{{ include "exporter.kubeScheduler.jobName" . }}\",instance=~\"$instance\"}", + "format": "time_series", + "intervalFactor": 2, + "legendFormat": "{{`{{`}}instance{{`}}`}}", + "refId": "A" + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Goroutines", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": false, + "title": "Dashboard Row", + "titleSize": "h6", + "type": "row" + } + ], + "schemaVersion": 14, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": "cluster", + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubeScheduler.jobName" . }}\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "instance", + "options": [ + + ], + "query": "label_values(up{job=\"{{ include "exporter.kubeScheduler.jobName" . }}\", cluster=\"$cluster\"}, instance)", + "refresh": 2, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Scheduler", + "uid": "2e6b6a3b4bddf1427b3a55aa1311c656", + "version": 0 + } +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/workload-total.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/workload-total.yaml new file mode 100644 index 0000000000..8784c7116c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/dashboards-1.14/workload-total.yaml @@ -0,0 +1,1438 @@ +{{- /* +Generated from 'workload-total' from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/b5b59bc0b45508b85647eb7a84b96dc167be15f1/manifests/grafana-dashboardDefinitions.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (or .Values.grafana.enabled .Values.grafana.forceDeployDashboards) (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "workload-total" | trunc 63 | trimSuffix "-" }} + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: {{ ternary $.Values.grafana.sidecar.dashboards.labelValue "1" (not (empty $.Values.grafana.sidecar.dashboards.labelValue)) | quote }} + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: + workload-total.json: |- + { + "__inputs": [ + + ], + "__requires": [ + + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ + + ], + "panels": [ + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Current Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 3, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}} pod {{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Received", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}} pod {{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Current Rate of Bytes Transmitted", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 5, + "panels": [ + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 6, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(avg(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}} pod {{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Rate of Bytes Received", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 7, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "links": [ + + ], + "minSpan": 24, + "nullPointMode": "null", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 24, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(avg(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}} pod {{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Rate of Bytes Transmitted", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Average Bandwidth", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": false, + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 8, + "panels": [ + + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Bandwidth HIstory", + "titleSize": "h6", + "type": "row" + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 12 + }, + "id": 9, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Receive Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 12 + }, + "id": 10, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_bytes_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Transmit Bandwidth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 11, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 22 + }, + "id": 12, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 22 + }, + "id": 13, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Packets", + "titleSize": "h6", + "type": "row" + }, + { + "collapse": true, + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 14, + "panels": [ + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 23 + }, + "id": 15, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_receive_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Received Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + }, + { + "aliasColors": { + + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 2, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 23 + }, + "id": 16, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "hideEmpty": true, + "hideZero": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [ + + ], + "minSpan": 12, + "nullPointMode": "connected", + "paceLength": 10, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ + + ], + "spaceLength": 10, + "span": 12, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sort_desc(sum(irate(container_network_transmit_packets_dropped_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\",namespace=~\"$namespace\"}[$interval:$resolution])\n* on (namespace,pod)\ngroup_left(workload,workload_type) namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\", workload_type=\"$type\"}) by (pod))\n", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{`{{`}}pod{{`}}`}}", + "refId": "A", + "step": 10 + } + ], + "thresholds": [ + + ], + "timeFrom": null, + "timeShift": null, + "title": "Rate of Transmitted Packets Dropped", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ + + ] + }, + "yaxes": [ + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "pps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] + } + ], + "repeat": null, + "repeatIteration": null, + "repeatRowId": null, + "showTitle": true, + "title": "Errors", + "titleSize": "h6", + "type": "row" + } + ], + "refresh": "10s", + "rows": [ + + ], + "schemaVersion": 18, + "style": "dark", + "tags": [ + "kubernetes-mixin" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "Prometheus" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ + + ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": null, + "current": { + + }, + "datasource": "$datasource", + "hide": {{ if .Values.grafana.sidecar.dashboards.multicluster.global.enabled }}0{{ else }}2{{ end }}, + "includeAll": false, + "label": null, + "multi": false, + "name": "cluster", + "options": [ + + ], + "query": "label_values(kube_pod_info{job=\"kube-state-metrics\"}, cluster)", + "refresh": 2, + "regex": "", + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".+", + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "kube-system", + "value": "kube-system" + }, + "datasource": "$datasource", + "definition": "label_values(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\"}, namespace)", + "hide": 0, + "includeAll": true, + "label": null, + "multi": false, + "name": "namespace", + "options": [ + + ], + "query": "label_values(container_network_receive_packets_total{job=\"{{ include "exporter.kubelet.jobName" . }}\", metrics_path=\"/metrics/cadvisor\", cluster=\"$cluster\"}, namespace)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "", + "value": "" + }, + "datasource": "$datasource", + "definition": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\"}, workload)", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "workload", + "options": [ + + ], + "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\"}, workload)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "deployment", + "value": "deployment" + }, + "datasource": "$datasource", + "definition": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\"}, workload_type)", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "type", + "options": [ + + ], + "query": "label_values(namespace_workload_pod:kube_pod_owner:relabel{cluster=\"$cluster\",namespace=~\"$namespace\", workload=~\"$workload\"}, workload_type)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "resolution", + "options": [ + { + "selected": false, + "text": "30s", + "value": "30s" + }, + { + "selected": true, + "text": "5m", + "value": "5m" + }, + { + "selected": false, + "text": "1h", + "value": "1h" + } + ], + "query": "30s,5m,1h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + }, + { + "allValue": null, + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "5m", + "value": "5m" + }, + "datasource": "$datasource", + "hide": 2, + "includeAll": false, + "label": null, + "multi": false, + "name": "interval", + "options": [ + { + "selected": true, + "text": "4h", + "value": "4h" + } + ], + "query": "4h", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [ + + ], + "tagsQuery": "", + "type": "interval", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "{{ .Values.grafana.defaultDashboardsTimezone }}", + "title": "Kubernetes / Networking / Workload", + "uid": "728bf77cc1166d2f3133bf25846876cc", + "version": 0 + } +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/namespaces.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/namespaces.yaml new file mode 100644 index 0000000000..39ed210ed4 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/grafana/namespaces.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled (not .Values.grafana.defaultDashboards.useExistingNamespace) }} +apiVersion: v1 +kind: Namespace +metadata: + name: {{ .Values.grafana.defaultDashboards.namespace }} + labels: + name: {{ .Values.grafana.defaultDashboards.namespace }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + annotations: +{{- if not .Values.grafana.defaultDashboards.cleanupOnUninstall }} + helm.sh/resource-policy: "keep" +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/_prometheus-operator.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/_prometheus-operator.tpl new file mode 100644 index 0000000000..6ae9dc72e6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/_prometheus-operator.tpl @@ -0,0 +1,7 @@ +{{/* Generate basic labels for prometheus-operator */}} +{{- define "kube-prometheus-stack.prometheus-operator.labels" }} +{{- include "kube-prometheus-stack.labels" . }} +app: {{ template "kube-prometheus-stack.name" . }}-operator +app.kubernetes.io/name: {{ template "kube-prometheus-stack.name" . }}-prometheus-operator +app.kubernetes.io/component: prometheus-operator +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/_prometheus-operator-webhook.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/_prometheus-operator-webhook.tpl new file mode 100644 index 0000000000..f419caf54b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/_prometheus-operator-webhook.tpl @@ -0,0 +1,6 @@ +{{/* Generate basic labels for prometheus-operator-webhook */}} +{{- define "kube-prometheus-stack.prometheus-operator-webhook.labels" }} +{{- include "kube-prometheus-stack.labels" . }} +app.kubernetes.io/name: {{ template "kube-prometheus-stack.name" . }}-prometheus-operator +app.kubernetes.io/component: prometheus-operator-webhook +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/deployment.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/deployment.yaml new file mode 100644 index 0000000000..054eac4a77 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/deployment.yaml @@ -0,0 +1,143 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.deployment.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }}-webhook + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-operator-webhook + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" . | nindent 4 }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.labels }} +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.labels | indent 4 }} +{{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.annotations }} + annotations: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.annotations | indent 4 }} +{{- end }} +spec: + replicas: {{ .Values.prometheusOperator.admissionWebhooks.deployment.replicas }} + revisionHistoryLimit: {{ .Values.prometheusOperator.admissionWebhooks.deployment.revisionHistoryLimit }} + {{- with .Values.prometheusOperator.admissionWebhooks.deployment.strategy }} + strategy: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-operator-webhook + release: {{ $.Release.Name | quote }} + template: + metadata: + labels: + app: {{ template "kube-prometheus-stack.name" . }}-operator-webhook + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" . | nindent 8 }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.podLabels }} +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.podLabels | indent 8 }} +{{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.podAnnotations }} + annotations: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.podAnnotations | indent 8 }} +{{- end }} + spec: + {{- if .Values.prometheusOperator.admissionWebhooks.deployment.priorityClassName }} + priorityClassName: {{ .Values.prometheusOperator.admissionWebhooks.deployment.priorityClassName }} + {{- end }} + {{- if .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- include "kube-prometheus-stack.imagePullSecrets" . | indent 8 }} + {{- end }} + containers: + - name: prometheus-operator-admission-webhook + {{- $operatorRegistry := .Values.global.imageRegistry | default .Values.prometheusOperator.admissionWebhooks.deployment.image.registry -}} + {{- if .Values.prometheusOperator.admissionWebhooks.deployment.image.sha }} + image: "{{ $operatorRegistry }}/{{ .Values.prometheusOperator.admissionWebhooks.deployment.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.deployment.image.tag | default .Chart.AppVersion }}@sha256:{{ .Values.prometheusOperator.admissionWebhooks.deployment.image.sha }}" + {{- else }} + image: "{{ $operatorRegistry }}/{{ .Values.prometheusOperator.admissionWebhooks.deployment.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.deployment.image.tag | default .Chart.AppVersion }}" + {{- end }} + imagePullPolicy: "{{ .Values.prometheusOperator.admissionWebhooks.deployment.image.pullPolicy }}" + args: + {{- if .Values.prometheusOperator.admissionWebhooks.deployment.logFormat }} + - --log-format={{ .Values.prometheusOperator.admissionWebhooks.deployment.logFormat }} + {{- end }} + {{- if .Values.prometheusOperator.admissionWebhooks.deployment.logLevel }} + - --log-level={{ .Values.prometheusOperator.admissionWebhooks.deployment.logLevel }} + {{- end }} + {{- if .Values.prometheusOperator.admissionWebhooks.deployment.tls.enabled }} + - "--web.enable-tls=true" + - "--web.cert-file=/cert/{{ if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}tls.crt{{ else }}cert{{ end }}" + - "--web.key-file=/cert/{{ if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}tls.key{{ else }}key{{ end }}" + - "--web.listen-address=:{{ .Values.prometheusOperator.admissionWebhooks.deployment.tls.internalPort }}" + - "--web.tls-min-version={{ .Values.prometheusOperator.admissionWebhooks.deployment.tls.tlsMinVersion }}" + ports: + - containerPort: {{ .Values.prometheusOperator.admissionWebhooks.deployment.tls.internalPort }} + name: https + {{- else }} + ports: + - containerPort: 8080 + name: http + {{- end }} + {{- if .Values.prometheusOperator.admissionWebhooks.deployment.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /healthz + port: {{ .Values.prometheusOperator.admissionWebhooks.deployment.tls.enabled | ternary "https" "http" }} + scheme: {{ .Values.prometheusOperator.admissionWebhooks.deployment.tls.enabled | ternary "HTTPS" "HTTP" }} + initialDelaySeconds: {{ .Values.prometheusOperator.admissionWebhooks.deployment.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.prometheusOperator.admissionWebhooks.deployment.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.prometheusOperator.admissionWebhooks.deployment.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.prometheusOperator.admissionWebhooks.deployment.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.prometheusOperator.admissionWebhooks.deployment.readinessProbe.failureThreshold }} + {{- end }} + {{- if .Values.prometheusOperator.admissionWebhooks.deployment.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: {{ .Values.prometheusOperator.admissionWebhooks.deployment.tls.enabled | ternary "https" "http" }} + scheme: {{ .Values.prometheusOperator.admissionWebhooks.deployment.tls.enabled | ternary "HTTPS" "HTTP" }} + initialDelaySeconds: {{ .Values.prometheusOperator.admissionWebhooks.deployment.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.prometheusOperator.admissionWebhooks.deployment.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.prometheusOperator.admissionWebhooks.deployment.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.prometheusOperator.admissionWebhooks.deployment.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.prometheusOperator.admissionWebhooks.deployment.livenessProbe.failureThreshold }} + {{- end }} + resources: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.resources | indent 12 }} + securityContext: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.containerSecurityContext | indent 12 }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.tls.enabled }} + volumeMounts: + - name: tls-secret + mountPath: /cert + readOnly: true + volumes: + - name: tls-secret + secret: + defaultMode: 420 + secretName: {{ template "kube-prometheus-stack.fullname" . }}-admission +{{- end }} + {{- with .Values.prometheusOperator.admissionWebhooks.deployment.dnsConfig }} + dnsConfig: +{{ toYaml . | indent 8 }} + {{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.securityContext }} + securityContext: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.securityContext | indent 8 }} +{{- end }} + serviceAccountName: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }}-webhook + automountServiceAccountToken: {{ .Values.prometheusOperator.admissionWebhooks.deployment.automountServiceAccountToken }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.hostNetwork }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet +{{- end }} + {{- with .Values.prometheusOperator.admissionWebhooks.deployment.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.prometheusOperator.admissionWebhooks.deployment.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.prometheusOperator.admissionWebhooks.deployment.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/pdb.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/pdb.yaml new file mode 100644 index 0000000000..04458b9675 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/pdb.yaml @@ -0,0 +1,15 @@ +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.podDisruptionBudget -}} +apiVersion: {{ include "kube-prometheus-stack.pdb.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }}-webhook + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-operator-webhook + release: {{ $.Release.Name | quote }} +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.podDisruptionBudget | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/service.yaml new file mode 100644 index 0000000000..6de9cbb71d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/service.yaml @@ -0,0 +1,62 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.deployment.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }}-webhook + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-operator-webhook + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" . | nindent 4 }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.service.labels }} +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.service.labels | indent 4 }} +{{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.service.annotations }} + annotations: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.service.annotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.service.clusterIP }} + clusterIP: {{ .Values.prometheusOperator.admissionWebhooks.deployment.service.clusterIP }} +{{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.prometheusOperator.admissionWebhooks.deployment.service.ipDualStack.ipFamilyPolicy }} +{{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.service.externalIPs }} + externalIPs: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.deployment.service.externalIPs | indent 4 }} +{{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.prometheusOperator.admissionWebhooks.deployment.service.loadBalancerIP }} +{{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.deployment.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.prometheusOperator.admissionWebhooks.deployment.service.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} +{{- end }} +{{- if ne .Values.prometheusOperator.admissionWebhooks.deployment.service.type "ClusterIP" }} + externalTrafficPolicy: {{ .Values.prometheusOperator.admissionWebhooks.deployment.service.externalTrafficPolicy }} +{{- end }} + ports: + {{- if not .Values.prometheusOperator.admissionWebhooks.deployment.tls.enabled }} + - name: http + {{- if eq .Values.prometheusOperator.admissionWebhooks.deployment.service.type "NodePort" }} + nodePort: {{ .Values.prometheusOperator.admissionWebhooks.deployment.service.nodePort }} + {{- end }} + port: 8080 + targetPort: http + {{- end }} + {{- if .Values.prometheusOperator.admissionWebhooks.deployment.tls.enabled }} + - name: https + {{- if eq .Values.prometheusOperator.admissionWebhooks.deployment.service.type "NodePort"}} + nodePort: {{ .Values.prometheusOperator.admissionWebhooks.deployment.service.nodePortTls }} + {{- end }} + port: 443 + targetPort: https + {{- end }} + selector: + app: {{ template "kube-prometheus-stack.name" . }}-operator-webhook + release: {{ $.Release.Name | quote }} + type: "{{ .Values.prometheusOperator.admissionWebhooks.deployment.service.type }}" +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/serviceaccount.yaml new file mode 100644 index 0000000000..55511da36b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/deployment/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.deployment.enabled }} +apiVersion: v1 +kind: ServiceAccount +automountServiceAccountToken: {{ .Values.prometheusOperator.admissionWebhooks.deployment.serviceAccount.automountServiceAccountToken }} +metadata: + name: {{ template "kube-prometheus-stack.operator.admissionWebhooks.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-operator + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" . | indent 4 }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-createSecret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-createSecret.yaml new file mode 100644 index 0000000000..f7543b0f1a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-createSecret.yaml @@ -0,0 +1,36 @@ +{{- if and .Values.prometheusOperator.networkPolicy.enabled (eq .Values.prometheusOperator.networkPolicy.flavor "cilium") }} +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission-create + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + helm.sh/hook: pre-install,pre-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + ## Ensure this is run before the job + helm.sh/hook-weight: "-5" + {{- with .Values.prometheusOperator.admissionWebhooks.annotations }} + {{ toYaml . | nindent 4 }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-create + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +spec: + endpointSelector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-create + {{- if .Values.prometheusOperator.networkPolicy.matchLabels }} + {{ toYaml .Values.prometheusOperator.networkPolicy.matchLabels | nindent 6 }} + {{- else }} + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 6 }} + {{- end }} + egress: + {{- if and .Values.prometheusOperator.networkPolicy.cilium .Values.prometheusOperator.networkPolicy.cilium.egress }} + {{ toYaml .Values.prometheusOperator.networkPolicy.cilium.egress | nindent 6 }} + {{- else }} + - toEntities: + - kube-apiserver + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-patchWebhook.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-patchWebhook.yaml new file mode 100644 index 0000000000..4e3b0d9225 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-patchWebhook.yaml @@ -0,0 +1,36 @@ +{{- if and .Values.prometheusOperator.networkPolicy.enabled (eq .Values.prometheusOperator.networkPolicy.flavor "cilium") }} +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission-patch + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + helm.sh/hook: post-install,post-upgrade + helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded + ## Ensure this is run before the job + helm.sh/hook-weight: "-5" + {{- with .Values.prometheusOperator.admissionWebhooks.patch.annotations }} + {{ toYaml . | nindent 4 }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-patch + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +spec: + endpointSelector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-patch + {{- if .Values.prometheusOperator.networkPolicy.matchLabels }} + {{ toYaml .Values.prometheusOperator.networkPolicy.matchLabels | nindent 6 }} + {{- else }} + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 6 }} + {{- end }} + egress: + {{- if and .Values.prometheusOperator.networkPolicy.cilium .Values.prometheusOperator.networkPolicy.cilium.egress }} + {{ toYaml .Values.prometheusOperator.networkPolicy.cilium.egress | nindent 6 }} + {{- else }} + - toEntities: + - kube-apiserver + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/clusterrole.yaml new file mode 100644 index 0000000000..1695490354 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/clusterrole.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "kube-prometheus-stack.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 "kube-prometheus-stack.name" $ }}-admission + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +rules: + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + - mutatingwebhookconfigurations + verbs: + - get + - update +{{- if and (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") .Values.global.rbac.pspEnabled }} +{{- $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-prometheus-stack.fullname" . }}-admission +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/clusterrolebinding.yaml new file mode 100644 index 0000000000..4cf1335b22 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "kube-prometheus-stack.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 "kube-prometheus-stack.name" $ }}-admission + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "kube-prometheus-stack.fullname" . }}-admission +subjects: + - kind: ServiceAccount + name: {{ template "kube-prometheus-stack.fullname" . }}-admission + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/job-createSecret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/job-createSecret.yaml new file mode 100644 index 0000000000..baed83db48 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/job-createSecret.yaml @@ -0,0 +1,73 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission-create + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +{{- with .Values.prometheusOperator.admissionWebhooks.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-create + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +spec: + {{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }} + # Alpha feature since k8s 1.12 + ttlSecondsAfterFinished: 0 + {{- end }} + template: + metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission-create +{{- with .Values.prometheusOperator.admissionWebhooks.patch.podAnnotations }} + annotations: +{{ toYaml . | indent 8 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-create + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 8 }} + spec: + {{- if .Values.prometheusOperator.admissionWebhooks.patch.priorityClassName }} + priorityClassName: {{ .Values.prometheusOperator.admissionWebhooks.patch.priorityClassName }} + {{- end }} + containers: + - name: create + {{- $registry := include "monitoring_registry" . | default .Values.prometheusOperator.admissionWebhooks.patch.image.registry -}} + {{- if .Values.prometheusOperator.admissionWebhooks.patch.image.sha }} + image: {{ $registry }}/{{ .Values.prometheusOperator.admissionWebhooks.patch.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.tag }}@sha256:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.sha }} + {{- else }} + image: {{ $registry }}/{{ .Values.prometheusOperator.admissionWebhooks.patch.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.tag }} + {{- end }} + imagePullPolicy: {{ .Values.prometheusOperator.admissionWebhooks.patch.image.pullPolicy }} + args: + - create + - --host={{- include "kube-prometheus-stack.operator.admission-webhook.dnsNames" . | replace "\n" "," }} + - --namespace={{ template "kube-prometheus-stack.namespace" . }} + - --secret-name={{ template "kube-prometheus-stack.fullname" . }}-admission + {{- with .Values.prometheusOperator.admissionWebhooks.createSecretJob }} + securityContext: + {{ toYaml .securityContext | nindent 12 }} + {{- end }} + resources: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.patch.resources | indent 12 }} + restartPolicy: OnFailure + serviceAccountName: {{ template "kube-prometheus-stack.fullname" . }}-admission + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- with .Values.prometheusOperator.admissionWebhooks.patch.nodeSelector }} +{{ toYaml . | indent 8 }} +{{- end }} + {{- with .Values.prometheusOperator.admissionWebhooks.patch.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- with .Values.prometheusOperator.admissionWebhooks.patch.tolerations }} +{{ toYaml . | indent 8 }} + {{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.patch.securityContext }} + securityContext: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.patch.securityContext | indent 8 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/job-patchWebhook.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/job-patchWebhook.yaml new file mode 100644 index 0000000000..5639cc9e80 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/job-patchWebhook.yaml @@ -0,0 +1,74 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission-patch + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +{{- with .Values.prometheusOperator.admissionWebhooks.patch.annotations }} +{{ toYaml . | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-patch + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +spec: + {{- if .Capabilities.APIVersions.Has "batch/v1alpha1" }} + # Alpha feature since k8s 1.12 + ttlSecondsAfterFinished: 0 + {{- end }} + template: + metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission-patch +{{- with .Values.prometheusOperator.admissionWebhooks.patch.podAnnotations }} + annotations: +{{ toYaml . | indent 8 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-patch + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 8 }} + spec: + {{- if .Values.prometheusOperator.admissionWebhooks.patch.priorityClassName }} + priorityClassName: {{ .Values.prometheusOperator.admissionWebhooks.patch.priorityClassName }} + {{- end }} + containers: + - name: patch + {{- $registry := include "monitoring_registry" . | default .Values.prometheusOperator.admissionWebhooks.patch.image.registry -}} + {{- if .Values.prometheusOperator.admissionWebhooks.patch.image.sha }} + image: {{ $registry }}/{{ .Values.prometheusOperator.admissionWebhooks.patch.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.tag }}@sha256:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.sha }} + {{- else }} + image: {{ $registry }}/{{ .Values.prometheusOperator.admissionWebhooks.patch.image.repository }}:{{ .Values.prometheusOperator.admissionWebhooks.patch.image.tag }} + {{- end }} + imagePullPolicy: {{ .Values.prometheusOperator.admissionWebhooks.patch.image.pullPolicy }} + args: + - patch + - --webhook-name={{ template "kube-prometheus-stack.fullname" . }}-admission + - --namespace={{ template "kube-prometheus-stack.namespace" . }} + - --secret-name={{ template "kube-prometheus-stack.fullname" . }}-admission + - --patch-failure-policy={{ .Values.prometheusOperator.admissionWebhooks.failurePolicy }} + {{- with .Values.prometheusOperator.admissionWebhooks.patchWebhookJob }} + securityContext: + {{ toYaml .securityContext | nindent 12 }} + {{- end }} + resources: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.patch.resources | indent 12 }} + restartPolicy: OnFailure + serviceAccountName: {{ template "kube-prometheus-stack.fullname" . }}-admission + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- with .Values.prometheusOperator.admissionWebhooks.patch.nodeSelector }} +{{ toYaml . | indent 8 }} +{{- end }} + {{- with .Values.prometheusOperator.admissionWebhooks.patch.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- with .Values.prometheusOperator.admissionWebhooks.patch.tolerations }} +{{ toYaml . | indent 8 }} + {{- end }} +{{- if .Values.prometheusOperator.admissionWebhooks.patch.securityContext }} + securityContext: +{{ toYaml .Values.prometheusOperator.admissionWebhooks.patch.securityContext | indent 8 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-createSecret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-createSecret.yaml new file mode 100644 index 0000000000..864deb52a0 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-createSecret.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.prometheusOperator.networkPolicy.enabled (eq .Values.prometheusOperator.networkPolicy.flavor "kubernetes") }} +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission-create + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + ## Ensure this is run before the job + "helm.sh/hook-weight": "-5" + {{- with .Values.prometheusOperator.admissionWebhooks.annotations }} + {{ toYaml . | nindent 4 }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-create + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +spec: + podSelector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-create + {{- if .Values.prometheusOperator.networkPolicy.matchLabels }} + {{ toYaml .Values.prometheusOperator.networkPolicy.matchLabels | nindent 6 }} + {{- else }} + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 6 }} + {{- end }} + egress: + - {} + policyTypes: + - Egress +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-patchWebhook.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-patchWebhook.yaml new file mode 100644 index 0000000000..076c467004 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-patchWebhook.yaml @@ -0,0 +1,33 @@ +{{- if and .Values.prometheusOperator.networkPolicy.enabled (eq .Values.prometheusOperator.networkPolicy.flavor "kubernetes") }} +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission-patch + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + ## Ensure this is run before the job + "helm.sh/hook-weight": "-5" + {{- with .Values.prometheusOperator.admissionWebhooks.patch.annotations }} + {{ toYaml . | nindent 4 }} + {{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-patch + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +spec: + podSelector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission-patch + {{- if .Values.prometheusOperator.networkPolicy.matchLabels }} + {{ toYaml .Values.prometheusOperator.networkPolicy.matchLabels | nindent 6 }} + {{- else }} + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 6 }} + {{- end }} + egress: + - {} + policyTypes: + - Egress +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/psp.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/psp.yaml new file mode 100644 index 0000000000..92c624001b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/psp.yaml @@ -0,0 +1,47 @@ +{{- if and (.Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy") .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +{{- if .Values.global.rbac.pspAnnotations }} +{{ toYaml .Values.global.rbac.pspAnnotations | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-admission + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" . | nindent 4 }} +spec: + privileged: false + # 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: + # Allow adding the root group. + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Allow adding the root group. + - min: 0 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/role.yaml new file mode 100644 index 0000000000..f15abf4395 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/role.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - create +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/rolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/rolebinding.yaml new file mode 100644 index 0000000000..30bde920b6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/rolebinding.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.global.rbac.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "kube-prometheus-stack.fullname" . }}-admission +subjects: + - kind: ServiceAccount + name: {{ template "kube-prometheus-stack.fullname" . }}-admission + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/serviceaccount.yaml new file mode 100644 index 0000000000..8dab40c609 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/job-patch/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled .Values.prometheusOperator.admissionWebhooks.patch.enabled .Values.prometheusOperator.admissionWebhooks.patch.serviceAccount.create (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +automountServiceAccountToken: {{ .Values.prometheusOperator.admissionWebhooks.patch.serviceAccount.automountServiceAccountToken }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/mutatingWebhookConfiguration.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/mutatingWebhookConfiguration.yaml new file mode 100644 index 0000000000..91d96b3845 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/mutatingWebhookConfiguration.yaml @@ -0,0 +1,81 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled }} +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission +{{- if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-admission" (include "kube-prometheus-stack.namespace" .) (include "kube-prometheus-stack.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-admission" (include "kube-prometheus-stack.namespace" .) (include "kube-prometheus-stack.fullname" .) | quote }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +webhooks: + - name: prometheusrulemutate.monitoring.coreos.com + {{- if eq .Values.prometheusOperator.admissionWebhooks.failurePolicy "IgnoreOnInstallOnly" }} + failurePolicy: {{ .Release.IsInstall | ternary "Ignore" "Fail" }} + {{- else if .Values.prometheusOperator.admissionWebhooks.failurePolicy }} + failurePolicy: {{ .Values.prometheusOperator.admissionWebhooks.failurePolicy }} + {{- else if .Values.prometheusOperator.admissionWebhooks.patch.enabled }} + failurePolicy: Ignore + {{- else }} + failurePolicy: Fail + {{- end }} + rules: + - apiGroups: + - monitoring.coreos.com + apiVersions: + - "*" + resources: + - prometheusrules + operations: + - CREATE + - UPDATE + clientConfig: + service: + namespace: {{ template "kube-prometheus-stack.namespace" . }} + name: {{ template "kube-prometheus-stack.operator.fullname" $ }}{{ if .Values.prometheusOperator.admissionWebhooks.deployment.enabled }}-webhook{{ end }} + path: /admission-prometheusrules/mutate + {{- if and .Values.prometheusOperator.admissionWebhooks.caBundle (not .Values.prometheusOperator.admissionWebhooks.patch.enabled) (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} + caBundle: {{ .Values.prometheusOperator.admissionWebhooks.caBundle }} + {{- end }} + timeoutSeconds: {{ .Values.prometheusOperator.admissionWebhooks.timeoutSeconds }} + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + {{- if or .Values.prometheusOperator.denyNamespaces .Values.prometheusOperator.namespaces .Values.prometheusOperator.admissionWebhooks.namespaceSelector }} + namespaceSelector: + {{- with (omit .Values.prometheusOperator.admissionWebhooks.namespaceSelector "matchExpressions") }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- if or .Values.prometheusOperator.denyNamespaces .Values.prometheusOperator.namespaces .Values.prometheusOperator.admissionWebhooks.namespaceSelector.matchExpressions }} + matchExpressions: + {{- with (.Values.prometheusOperator.admissionWebhooks.namespaceSelector.matchExpressions) }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- if .Values.prometheusOperator.denyNamespaces }} + - key: kubernetes.io/metadata.name + operator: NotIn + values: + {{- range $namespace := mustUniq .Values.prometheusOperator.denyNamespaces }} + - {{ $namespace }} + {{- end }} + {{- else if and .Values.prometheusOperator.namespaces .Values.prometheusOperator.namespaces.additional }} + - key: kubernetes.io/metadata.name + operator: In + values: + {{- if and .Values.prometheusOperator.namespaces.releaseNamespace (default .Values.prometheusOperator.namespaces.releaseNamespace true) }} + {{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }} + - {{ $namespace }} + {{- end }} + {{- range $namespace := mustUniq .Values.prometheusOperator.namespaces.additional }} + - {{ $namespace }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.prometheusOperator.admissionWebhooks.objectSelector }} + objectSelector: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/validatingWebhookConfiguration.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/validatingWebhookConfiguration.yaml new file mode 100644 index 0000000000..f21a9a72b1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/admission-webhooks/validatingWebhookConfiguration.yaml @@ -0,0 +1,81 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.admissionWebhooks.enabled }} +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission +{{- if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }} + annotations: + certmanager.k8s.io/inject-ca-from: {{ printf "%s/%s-admission" (include "kube-prometheus-stack.namespace" .) (include "kube-prometheus-stack.fullname" .) | quote }} + cert-manager.io/inject-ca-from: {{ printf "%s/%s-admission" (include "kube-prometheus-stack.namespace" .) (include "kube-prometheus-stack.fullname" .) | quote }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-admission + {{- include "kube-prometheus-stack.prometheus-operator-webhook.labels" $ | nindent 4 }} +webhooks: + - name: prometheusrulemutate.monitoring.coreos.com + {{- if eq .Values.prometheusOperator.admissionWebhooks.failurePolicy "IgnoreOnInstallOnly" }} + failurePolicy: {{ .Release.IsInstall | ternary "Ignore" "Fail" }} + {{- else if .Values.prometheusOperator.admissionWebhooks.failurePolicy }} + failurePolicy: {{ .Values.prometheusOperator.admissionWebhooks.failurePolicy }} + {{- else if .Values.prometheusOperator.admissionWebhooks.patch.enabled }} + failurePolicy: Ignore + {{- else }} + failurePolicy: Fail + {{- end }} + rules: + - apiGroups: + - monitoring.coreos.com + apiVersions: + - "*" + resources: + - prometheusrules + operations: + - CREATE + - UPDATE + clientConfig: + service: + namespace: {{ template "kube-prometheus-stack.namespace" . }} + name: {{ template "kube-prometheus-stack.operator.fullname" $ }}{{ if .Values.prometheusOperator.admissionWebhooks.deployment.enabled }}-webhook{{ end }} + path: /admission-prometheusrules/validate + {{- if and .Values.prometheusOperator.admissionWebhooks.caBundle (not .Values.prometheusOperator.admissionWebhooks.patch.enabled) (not .Values.prometheusOperator.admissionWebhooks.certManager.enabled) }} + caBundle: {{ .Values.prometheusOperator.admissionWebhooks.caBundle }} + {{- end }} + timeoutSeconds: {{ .Values.prometheusOperator.admissionWebhooks.timeoutSeconds }} + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + {{- if or .Values.prometheusOperator.denyNamespaces .Values.prometheusOperator.namespaces .Values.prometheusOperator.admissionWebhooks.namespaceSelector }} + namespaceSelector: + {{- with (omit .Values.prometheusOperator.admissionWebhooks.namespaceSelector "matchExpressions") }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- if or .Values.prometheusOperator.denyNamespaces .Values.prometheusOperator.namespaces .Values.prometheusOperator.admissionWebhooks.namespaceSelector.matchExpressions }} + matchExpressions: + {{- with (.Values.prometheusOperator.admissionWebhooks.namespaceSelector.matchExpressions) }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.prometheusOperator.denyNamespaces }} + - key: kubernetes.io/metadata.name + operator: NotIn + values: + {{- range $namespace := mustUniq .Values.prometheusOperator.denyNamespaces }} + - {{ $namespace }} + {{- end }} + {{- else if and .Values.prometheusOperator.namespaces .Values.prometheusOperator.namespaces.additional }} + - key: kubernetes.io/metadata.name + operator: In + values: + {{- if and .Values.prometheusOperator.namespaces.releaseNamespace (default .Values.prometheusOperator.namespaces.releaseNamespace true) }} + {{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }} + - {{ $namespace }} + {{- end }} + {{- range $namespace := mustUniq .Values.prometheusOperator.namespaces.additional }} + - {{ $namespace }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- with .Values.prometheusOperator.admissionWebhooks.objectSelector }} + objectSelector: + {{- toYaml . | nindent 6 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/aggregate-clusterroles.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/aggregate-clusterroles.yaml new file mode 100644 index 0000000000..0c52000d6d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/aggregate-clusterroles.yaml @@ -0,0 +1,29 @@ +{{/* This file is based on https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/rbac-crd.md */}} +{{- if and .Values.global.rbac.create .Values.global.rbac.createAggregateClusterRoles }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-crd-view + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-view: "true" + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +rules: +- apiGroups: ["monitoring.coreos.com"] + resources: ["alertmanagers", "alertmanagerconfigs", "podmonitors", "probes", "prometheuses", "prometheusagents", "prometheusrules", "scrapeconfigs", "servicemonitors"] + verbs: ["get", "list", "watch"] +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-crd-edit + labels: + rbac.authorization.k8s.io/aggregate-to-edit: "true" + rbac.authorization.k8s.io/aggregate-to-admin: "true" + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +rules: +- apiGroups: ["monitoring.coreos.com"] + resources: ["alertmanagers", "alertmanagerconfigs", "podmonitors", "probes", "prometheuses", "prometheusagents", "prometheusrules", "scrapeconfigs", "servicemonitors"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/certmanager.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/certmanager.yaml new file mode 100644 index 0000000000..cb27e49f48 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/certmanager.yaml @@ -0,0 +1,55 @@ +{{- if .Values.prometheusOperator.admissionWebhooks.certManager.enabled -}} +{{- if not .Values.prometheusOperator.admissionWebhooks.certManager.issuerRef -}} +# Create a selfsigned Issuer, in order to create a root CA certificate for +# signing webhook serving certificates +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-self-signed-issuer + namespace: {{ template "kube-prometheus-stack.namespace" . }} +spec: + selfSigned: {} +--- +# Generate a CA Certificate used to sign certificates for the webhook +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-root-cert + namespace: {{ template "kube-prometheus-stack.namespace" . }} +spec: + secretName: {{ template "kube-prometheus-stack.fullname" . }}-root-cert + duration: {{ .Values.prometheusOperator.admissionWebhooks.certManager.rootCert.duration | default "43800h0m0s" | quote }} + issuerRef: + name: {{ template "kube-prometheus-stack.fullname" . }}-self-signed-issuer + commonName: "ca.webhook.kube-prometheus-stack" + isCA: true +--- +# Create an Issuer that uses the above generated CA certificate to issue certs +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-root-issuer + namespace: {{ template "kube-prometheus-stack.namespace" . }} +spec: + ca: + secretName: {{ template "kube-prometheus-stack.fullname" . }}-root-cert +{{- end }} +--- +# generate a server certificate for the apiservices to use +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission + namespace: {{ template "kube-prometheus-stack.namespace" . }} +spec: + secretName: {{ template "kube-prometheus-stack.fullname" . }}-admission + duration: {{ .Values.prometheusOperator.admissionWebhooks.certManager.admissionCert.duration | default "8760h0m0s" | quote }} + issuerRef: + {{- if .Values.prometheusOperator.admissionWebhooks.certManager.issuerRef }} + {{- toYaml .Values.prometheusOperator.admissionWebhooks.certManager.issuerRef | nindent 4 }} + {{- else }} + name: {{ template "kube-prometheus-stack.fullname" . }}-root-issuer + {{- end }} + dnsNames: + {{- include "kube-prometheus-stack.operator.admission-webhook.dnsNames" . | splitList "\n" | toYaml | nindent 4 }} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/ciliumnetworkpolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/ciliumnetworkpolicy.yaml new file mode 100644 index 0000000000..07e2e99967 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/ciliumnetworkpolicy.yaml @@ -0,0 +1,40 @@ +{{- if and .Values.prometheusOperator.networkPolicy.enabled (eq .Values.prometheusOperator.networkPolicy.flavor "cilium") }} +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +spec: + endpointSelector: + matchLabels: + {{- if .Values.prometheusOperator.networkPolicy.matchLabels }} + app: {{ template "kube-prometheus-stack.name" . }}-operator + {{ toYaml .Values.prometheusOperator.networkPolicy.matchLabels | nindent 6 }} + {{- else }} + {{- include "kube-prometheus-stack.prometheus-operator.labels" $ | nindent 6 }} + {{- end }} + egress: + {{- if and .Values.prometheusOperator.networkPolicy.cilium .Values.prometheusOperator.networkPolicy.cilium.egress }} + {{ toYaml .Values.prometheusOperator.networkPolicy.cilium.egress | nindent 6 }} + {{- else }} + - toEntities: + - kube-apiserver + {{- end }} + ingress: + - toPorts: + - ports: + {{- if .Values.prometheusOperator.tls.enabled }} + - port: {{ .Values.prometheusOperator.tls.internalPort | quote }} + {{- else }} + - port: "8080" + {{- end }} + protocol: "TCP" + {{- if not .Values.prometheusOperator.tls.enabled }} + rules: + http: + - method: "GET" + path: "/metrics" + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/clusterrole.yaml new file mode 100644 index 0000000000..fd11b69eed --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/clusterrole.yaml @@ -0,0 +1,109 @@ +{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +rules: +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - alertmanagers/finalizers + - alertmanagers/status + - alertmanagerconfigs + - prometheuses + - prometheuses/finalizers + - prometheuses/status + - prometheusagents + - prometheusagents/finalizers + - prometheusagents/status + - thanosrulers + - thanosrulers/finalizers + - thanosrulers/status + - scrapeconfigs + - servicemonitors + - podmonitors + - probes + - prometheusrules + verbs: + - '*' +- apiGroups: + - apps + resources: + - statefulsets + verbs: + - '*' +- apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - '*' +- apiGroups: + - "" + resources: + - pods + verbs: + - list + - delete +- apiGroups: + - "" + resources: + - services + - services/finalizers + - endpoints + verbs: + - get + - create + - update + - delete +- apiGroups: + - "" + resources: + - nodes + verbs: + - list + - watch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - events + verbs: + - patch + - create +- apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - get + - list + - watch +- apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get +{{- if .Capabilities.APIVersions.Has "discovery.k8s.io/v1/EndpointSlice" }} +- apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/clusterrolebinding.yaml new file mode 100644 index 0000000000..ad9e3ef6c5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "kube-prometheus-stack.operator.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/deployment.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/deployment.yaml new file mode 100644 index 0000000000..b71e7d25d6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/deployment.yaml @@ -0,0 +1,207 @@ +{{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }} +{{- $defaultKubeletSvcName := printf "%s-kubelet" (include "kube-prometheus-stack.fullname" .) }} +{{- if .Values.prometheusOperator.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +{{- if .Values.prometheusOperator.labels }} +{{ toYaml .Values.prometheusOperator.labels | indent 4 }} +{{- end }} +{{- if .Values.prometheusOperator.annotations }} + annotations: +{{ toYaml .Values.prometheusOperator.annotations | indent 4 }} +{{- end }} +spec: + replicas: 1 + revisionHistoryLimit: {{ .Values.prometheusOperator.revisionHistoryLimit }} + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-operator + release: {{ $.Release.Name | quote }} + {{- with .Values.prometheusOperator.strategy }} + strategy: + {{- toYaml . | nindent 4 }} + {{- end }} + template: + metadata: + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 8 }} +{{- if .Values.prometheusOperator.podLabels }} +{{ toYaml .Values.prometheusOperator.podLabels | indent 8 }} +{{- end }} +{{- if .Values.prometheusOperator.podAnnotations }} + annotations: +{{ toYaml .Values.prometheusOperator.podAnnotations | indent 8 }} +{{- end }} + spec: + {{- if .Values.prometheusOperator.priorityClassName }} + priorityClassName: {{ .Values.prometheusOperator.priorityClassName }} + {{- end }} + {{- if .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- include "kube-prometheus-stack.imagePullSecrets" . | indent 8 }} + {{- end }} + containers: + - name: {{ template "kube-prometheus-stack.name" . }} + {{- $base_registry := (include "monitoring_registry" .) }} + {{- $configReloaderRegistry := $base_registry | default .Values.prometheusOperator.prometheusConfigReloader.image.registry -}} + {{- $operatorRegistry := $base_registry | default .Values.prometheusOperator.image.registry -}} + {{- $thanosRegistry := $base_registry | default .Values.prometheusOperator.thanosImage.registry -}} + {{- if .Values.prometheusOperator.image.sha }} + image: "{{ $operatorRegistry }}/{{ .Values.prometheusOperator.image.repository }}:{{ .Values.prometheusOperator.image.tag | default .Chart.AppVersion }}@sha256:{{ .Values.prometheusOperator.image.sha }}" + {{- else }} + image: "{{ $operatorRegistry }}/{{ .Values.prometheusOperator.image.repository }}:{{ .Values.prometheusOperator.image.tag | default .Chart.AppVersion }}" + {{- end }} + imagePullPolicy: "{{ .Values.prometheusOperator.image.pullPolicy }}" + args: + {{- if .Values.prometheusOperator.kubeletService.enabled }} + - --kubelet-service={{ .Values.prometheusOperator.kubeletService.namespace }}/{{ default $defaultKubeletSvcName .Values.prometheusOperator.kubeletService.name }} + {{- if .Values.prometheusOperator.kubeletService.selector }} + - --kubelet-selector={{ .Values.prometheusOperator.kubeletService.selector }} + {{- end }} + {{- end }} + {{- if .Values.prometheusOperator.logFormat }} + - --log-format={{ .Values.prometheusOperator.logFormat }} + {{- end }} + {{- if .Values.prometheusOperator.logLevel }} + - --log-level={{ .Values.prometheusOperator.logLevel }} + {{- end }} + {{- if .Values.prometheusOperator.denyNamespaces }} + - --deny-namespaces={{ tpl (.Values.prometheusOperator.denyNamespaces | join ",") $ }} + {{- end }} + {{- with $.Values.prometheusOperator.namespaces }} + {{- $namespaces := list }} + {{- if .releaseNamespace }} + {{- $namespaces = append $namespaces $namespace }} + {{- end }} + {{- if .additional }} + {{- range $ns := .additional }} + {{- $namespaces = append $namespaces (tpl $ns $) }} + {{- end }} + {{- end }} + - --namespaces={{ $namespaces | mustUniq | join "," }} + {{- end }} + - --localhost=127.0.0.1 + {{- if .Values.prometheusOperator.prometheusDefaultBaseImage }} + - --prometheus-default-base-image={{ $base_registry | default .Values.prometheusOperator.prometheusDefaultBaseImageRegistry }}/{{ .Values.prometheusOperator.prometheusDefaultBaseImage }} + {{- end }} + {{- if .Values.prometheusOperator.alertmanagerDefaultBaseImage }} + - --alertmanager-default-base-image={{ $base_registry | default .Values.prometheusOperator.alertmanagerDefaultBaseImageRegistry }}/{{ .Values.prometheusOperator.alertmanagerDefaultBaseImage }} + {{- end }} + {{- if .Values.prometheusOperator.prometheusConfigReloader.image.sha }} + - --prometheus-config-reloader={{ $configReloaderRegistry }}/{{ .Values.prometheusOperator.prometheusConfigReloader.image.repository }}:{{ .Values.prometheusOperator.prometheusConfigReloader.image.tag | default .Chart.AppVersion }}@sha256:{{ .Values.prometheusOperator.prometheusConfigReloader.image.sha }} + {{- else }} + - --prometheus-config-reloader={{ $configReloaderRegistry }}/{{ .Values.prometheusOperator.prometheusConfigReloader.image.repository }}:{{ .Values.prometheusOperator.prometheusConfigReloader.image.tag | default .Chart.AppVersion }} + {{- end }} + - --config-reloader-cpu-request={{ (((.Values.prometheusOperator.prometheusConfigReloader.resources).requests).cpu) | default 0 }} + - --config-reloader-cpu-limit={{ (((.Values.prometheusOperator.prometheusConfigReloader.resources).limits).cpu) | default 0 }} + - --config-reloader-memory-request={{ (((.Values.prometheusOperator.prometheusConfigReloader.resources).requests).memory) | default 0 }} + - --config-reloader-memory-limit={{ (((.Values.prometheusOperator.prometheusConfigReloader.resources).limits).memory) | default 0 }} + {{- if .Values.prometheusOperator.prometheusConfigReloader.enableProbe }} + - --enable-config-reloader-probes=true + {{- end }} + {{- if .Values.prometheusOperator.alertmanagerInstanceNamespaces }} + - --alertmanager-instance-namespaces={{ .Values.prometheusOperator.alertmanagerInstanceNamespaces | join "," }} + {{- end }} + {{- if .Values.prometheusOperator.alertmanagerInstanceSelector }} + - --alertmanager-instance-selector={{ .Values.prometheusOperator.alertmanagerInstanceSelector }} + {{- end }} + {{- if .Values.prometheusOperator.alertmanagerConfigNamespaces }} + - --alertmanager-config-namespaces={{ .Values.prometheusOperator.alertmanagerConfigNamespaces | join "," }} + {{- end }} + {{- if .Values.prometheusOperator.prometheusInstanceNamespaces }} + - --prometheus-instance-namespaces={{ .Values.prometheusOperator.prometheusInstanceNamespaces | join "," }} + {{- end }} + {{- if .Values.prometheusOperator.prometheusInstanceSelector }} + - --prometheus-instance-selector={{ .Values.prometheusOperator.prometheusInstanceSelector }} + {{- end }} + {{- if .Values.prometheusOperator.thanosImage.sha }} + - --thanos-default-base-image={{ $thanosRegistry }}/{{ .Values.prometheusOperator.thanosImage.repository }}:{{ .Values.prometheusOperator.thanosImage.tag }}@sha256:{{ .Values.prometheusOperator.thanosImage.sha }} + {{- else }} + - --thanos-default-base-image={{ $thanosRegistry }}/{{ .Values.prometheusOperator.thanosImage.repository }}:{{ .Values.prometheusOperator.thanosImage.tag }} + {{- end }} + {{- if .Values.prometheusOperator.thanosRulerInstanceNamespaces }} + - --thanos-ruler-instance-namespaces={{ .Values.prometheusOperator.thanosRulerInstanceNamespaces | join "," }} + {{- end }} + {{- if .Values.prometheusOperator.thanosRulerInstanceSelector }} + - --thanos-ruler-instance-selector={{ .Values.prometheusOperator.thanosRulerInstanceSelector }} + {{- end }} + {{- if .Values.prometheusOperator.secretFieldSelector }} + - --secret-field-selector={{ tpl (.Values.prometheusOperator.secretFieldSelector) $ }} + {{- end }} + {{- if .Values.prometheusOperator.clusterDomain }} + - --cluster-domain={{ .Values.prometheusOperator.clusterDomain }} + {{- end }} + {{- if .Values.prometheusOperator.tls.enabled }} + - --web.enable-tls=true + - --web.cert-file=/cert/{{ if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}tls.crt{{ else }}cert{{ end }} + - --web.key-file=/cert/{{ if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}tls.key{{ else }}key{{ end }} + - --web.listen-address=:{{ .Values.prometheusOperator.tls.internalPort }} + - --web.tls-min-version={{ .Values.prometheusOperator.tls.tlsMinVersion }} + ports: + - containerPort: {{ .Values.prometheusOperator.tls.internalPort }} + name: https + {{- else }} + ports: + - containerPort: 8080 + name: http + {{- end }} + env: + {{- range $key, $value := .Values.prometheusOperator.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + resources: +{{ toYaml .Values.prometheusOperator.resources | indent 12 }} + securityContext: +{{ toYaml .Values.prometheusOperator.containerSecurityContext | indent 12 }} + volumeMounts: + {{- if .Values.prometheusOperator.tls.enabled }} + - name: tls-secret + mountPath: /cert + readOnly: true + {{- end }} + {{- with .Values.prometheusOperator.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + volumes: + {{- if .Values.prometheusOperator.tls.enabled }} + - name: tls-secret + secret: + defaultMode: 420 + secretName: {{ template "kube-prometheus-stack.fullname" . }}-admission + {{- end }} + {{- with .Values.prometheusOperator.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.prometheusOperator.dnsConfig }} + dnsConfig: +{{ toYaml . | indent 8 }} + {{- end }} +{{- if .Values.prometheusOperator.securityContext }} + securityContext: +{{ toYaml .Values.prometheusOperator.securityContext | indent 8 }} +{{- end }} + serviceAccountName: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.prometheusOperator.automountServiceAccountToken }} +{{- if .Values.prometheusOperator.hostNetwork }} + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet +{{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} +{{- with .Values.prometheusOperator.nodeSelector }} +{{ toYaml . | indent 8 }} +{{- end }} + {{- with .Values.prometheusOperator.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} +{{- with .Values.prometheusOperator.tolerations }} +{{ toYaml . | indent 8 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/networkpolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/networkpolicy.yaml new file mode 100644 index 0000000000..cfd5b0b8c7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/networkpolicy.yaml @@ -0,0 +1,29 @@ +{{- if and .Values.prometheusOperator.networkPolicy.enabled (eq .Values.prometheusOperator.networkPolicy.flavor "kubernetes") }} +apiVersion: {{ template "kube-prometheus-stack.prometheus.networkPolicy.apiVersion" . }} +kind: NetworkPolicy +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +spec: + egress: + - {} + ingress: + - ports: + {{- if .Values.prometheusOperator.tls.enabled }} + - port: {{ .Values.prometheusOperator.tls.internalPort }} + {{- else }} + - port: 8080 + {{- end }} + policyTypes: + - Egress + - Ingress + podSelector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-operator + release: {{ $.Release.Name | quote }} + {{- if .Values.prometheusOperator.networkPolicy.matchLabels }} + {{ toYaml .Values.prometheusOperator.networkPolicy.matchLabels | nindent 6 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp-clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp-clusterrole.yaml new file mode 100644 index 0000000000..9766238968 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp-clusterrole.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }}-psp + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +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-prometheus-stack.operator.fullname" . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp-clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp-clusterrolebinding.yaml new file mode 100644 index 0000000000..01f5f3d9dd --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp-clusterrolebinding.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }}-psp + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "kube-prometheus-stack.operator.fullname" . }}-psp +subjects: + - kind: ServiceAccount + name: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp.yaml new file mode 100644 index 0000000000..0943b5f563 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/psp.yaml @@ -0,0 +1,46 @@ +{{- if and .Values.prometheusOperator.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +{{- if .Values.global.rbac.pspAnnotations }} + annotations: +{{ toYaml .Values.global.rbac.pspAnnotations | indent 4 }} +{{- end }} +spec: + privileged: false + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + - 'persistentVolumeClaim' + hostNetwork: {{ .Values.prometheusOperator.hostNetwork }} + 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: + # Allow adding the root group. + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Allow adding the root group. + - min: 0 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/service.yaml new file mode 100644 index 0000000000..72e0788abf --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/service.yaml @@ -0,0 +1,61 @@ +{{- if .Values.prometheusOperator.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +{{- if .Values.prometheusOperator.service.labels }} +{{ toYaml .Values.prometheusOperator.service.labels | indent 4 }} +{{- end }} +{{- if .Values.prometheusOperator.service.annotations }} + annotations: +{{ toYaml .Values.prometheusOperator.service.annotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.prometheusOperator.service.clusterIP }} + clusterIP: {{ .Values.prometheusOperator.service.clusterIP }} +{{- end }} +{{- if .Values.prometheusOperator.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.prometheusOperator.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.prometheusOperator.service.ipDualStack.ipFamilyPolicy }} +{{- end }} +{{- if .Values.prometheusOperator.service.externalIPs }} + externalIPs: +{{ toYaml .Values.prometheusOperator.service.externalIPs | indent 4 }} +{{- end }} +{{- if .Values.prometheusOperator.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.prometheusOperator.service.loadBalancerIP }} +{{- end }} +{{- if .Values.prometheusOperator.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.prometheusOperator.service.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} +{{- end }} +{{- if ne .Values.prometheusOperator.service.type "ClusterIP" }} + externalTrafficPolicy: {{ .Values.prometheusOperator.service.externalTrafficPolicy }} +{{- end }} + ports: + {{- if not .Values.prometheusOperator.tls.enabled }} + - name: http + {{- if eq .Values.prometheusOperator.service.type "NodePort" }} + nodePort: {{ .Values.prometheusOperator.service.nodePort }} + {{- end }} + port: 8080 + targetPort: http + {{- end }} + {{- if .Values.prometheusOperator.tls.enabled }} + - name: https + {{- if eq .Values.prometheusOperator.service.type "NodePort"}} + nodePort: {{ .Values.prometheusOperator.service.nodePortTls }} + {{- end }} + port: 443 + targetPort: https + {{- end }} + selector: + app: {{ template "kube-prometheus-stack.name" . }}-operator + release: {{ $.Release.Name | quote }} + type: "{{ .Values.prometheusOperator.service.type }}" +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/serviceaccount.yaml new file mode 100644 index 0000000000..4f84974f9b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/serviceaccount.yaml @@ -0,0 +1,14 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kube-prometheus-stack.operator.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +automountServiceAccountToken: {{ .Values.prometheusOperator.serviceAccount.automountServiceAccountToken }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/servicemonitor.yaml new file mode 100644 index 0000000000..cbe79e1253 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/servicemonitor.yaml @@ -0,0 +1,57 @@ +{{- if and .Values.prometheusOperator.enabled .Values.prometheusOperator.serviceMonitor.selfMonitor }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +{{- with .Values.prometheusOperator.serviceMonitor.additionalLabels }} +{{ toYaml . | indent 4 }} +{{- end }} +spec: + {{- include "servicemonitor.scrapeLimits" .Values.prometheusOperator.serviceMonitor | nindent 2 }} + endpoints: + {{- if .Values.prometheusOperator.tls.enabled }} + - port: https + scheme: https + tlsConfig: + serverName: {{ template "kube-prometheus-stack.operator.fullname" . }} + ca: + secret: + name: {{ template "kube-prometheus-stack.fullname" . }}-admission + key: {{ if .Values.prometheusOperator.admissionWebhooks.certManager.enabled }}ca.crt{{ else }}ca{{ end }} + optional: false + {{- else }} + - port: http + {{- end }} + honorLabels: true + {{- if .Values.prometheusOperator.serviceMonitor.interval }} + interval: {{ .Values.prometheusOperator.serviceMonitor.interval }} + {{- end }} + metricRelabelings: + {{- if .Values.prometheusOperator.serviceMonitor.metricRelabelings }} + {{ tpl (toYaml .Values.prometheusOperator.serviceMonitor.metricRelabelings | indent 6) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.prometheusOperator.serviceMonitor.relabelings }} + relabelings: +{{ toYaml .Values.prometheusOperator.serviceMonitor.relabelings | indent 6 }} +{{- end }} + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-operator + release: {{ $.Release.Name | quote }} + namespaceSelector: + matchNames: + - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/verticalpodautoscaler.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/verticalpodautoscaler.yaml new file mode 100644 index 0000000000..f225d16dde --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus-operator/verticalpodautoscaler.yaml @@ -0,0 +1,40 @@ +{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1") (.Values.prometheusOperator.verticalPodAutoscaler.enabled) }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + {{- include "kube-prometheus-stack.prometheus-operator.labels" . | nindent 4 }} +spec: + {{- with .Values.prometheusOperator.verticalPodAutoscaler.recommenders }} + recommenders: + {{- toYaml . | nindent 4 }} + {{- end }} + resourcePolicy: + containerPolicies: + - containerName: {{ template "kube-prometheus-stack.name" . }} + {{- with .Values.prometheusOperator.verticalPodAutoscaler.controlledResources }} + controlledResources: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.prometheusOperator.verticalPodAutoscaler.controlledValues }} + controlledValues: {{ .Values.prometheusOperator.verticalPodAutoscaler.controlledValues }} + {{- end }} + {{- if .Values.prometheusOperator.verticalPodAutoscaler.maxAllowed }} + maxAllowed: + {{- toYaml .Values.prometheusOperator.verticalPodAutoscaler.maxAllowed | nindent 8 }} + {{- end }} + {{- if .Values.prometheusOperator.verticalPodAutoscaler.minAllowed }} + minAllowed: + {{- toYaml .Values.prometheusOperator.verticalPodAutoscaler.minAllowed | nindent 8 }} + {{- end }} + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ template "kube-prometheus-stack.operator.fullname" . }} + {{- with .Values.prometheusOperator.verticalPodAutoscaler.updatePolicy }} + updatePolicy: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/_rules.tpl b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/_rules.tpl new file mode 100644 index 0000000000..4a8213d089 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/_rules.tpl @@ -0,0 +1,44 @@ +{{- /* +Generated file. Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- define "rules.names" }} +rules: + - "alertmanager.rules" + - "config-reloaders" + - "etcd" + - "general.rules" + - "k8s.rules.container-cpu-usage-seconds-total" + - "k8s.rules.container-memory-cache" + - "k8s.rules.container-memory-rss" + - "k8s.rules.container-memory-swap" + - "k8s.rules.container-memory-working-set-bytes" + - "k8s.rules.container-resource" + - "k8s.rules.pod-owner" + - "kube-apiserver-availability.rules" + - "kube-apiserver-burnrate.rules" + - "kube-apiserver-histogram.rules" + - "kube-apiserver-slos" + - "kube-prometheus-general.rules" + - "kube-prometheus-node-recording.rules" + - "kube-scheduler.rules" + - "kube-state-metrics" + - "kubelet.rules" + - "kubernetes-apps" + - "kubernetes-resources" + - "kubernetes-storage" + - "kubernetes-system" + - "kubernetes-system-kube-proxy" + - "kubernetes-system-apiserver" + - "kubernetes-system-kubelet" + - "kubernetes-system-controller-manager" + - "kubernetes-system-scheduler" + - "node-exporter.rules" + - "node-exporter" + - "node.rules" + - "node-network" + - "prometheus-operator" + - "prometheus" + - "windows.node.rules" + - "windows.pod.rules" +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalAlertRelabelConfigs.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalAlertRelabelConfigs.yaml new file mode 100644 index 0000000000..bff930981a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalAlertRelabelConfigs.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigs }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-am-relabel-confg + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- if .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations }} + annotations: +{{ toYaml .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus-am-relabel-confg +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: + additional-alert-relabel-configs.yaml: {{ toYaml .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigs | b64enc | quote }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalAlertmanagerConfigs.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalAlertmanagerConfigs.yaml new file mode 100644 index 0000000000..2fe8fdb816 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalAlertmanagerConfigs.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.prometheusSpec.additionalAlertManagerConfigs }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-am-confg + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- if .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations }} + annotations: +{{ toYaml .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus-am-confg +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: + additional-alertmanager-configs.yaml: {{ tpl (toYaml .Values.prometheus.prometheusSpec.additionalAlertManagerConfigs) . | b64enc | quote }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalPrometheusRules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalPrometheusRules.yaml new file mode 100644 index 0000000000..cb4aabaa7b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalPrometheusRules.yaml @@ -0,0 +1,43 @@ +{{- if or .Values.additionalPrometheusRules .Values.additionalPrometheusRulesMap}} +apiVersion: v1 +kind: List +metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-additional-prometheus-rules + namespace: {{ template "kube-prometheus-stack.namespace" . }} +items: +{{- if .Values.additionalPrometheusRulesMap }} +{{- range $prometheusRuleName, $prometheusRule := .Values.additionalPrometheusRulesMap }} + - apiVersion: monitoring.coreos.com/v1 + kind: PrometheusRule + metadata: + name: {{ template "kube-prometheus-stack.name" $ }}-{{ $prometheusRuleName }} + namespace: {{ template "kube-prometheus-stack.namespace" $ }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }} +{{ include "kube-prometheus-stack.labels" $ | indent 8 }} + {{- if $prometheusRule.additionalLabels }} +{{ toYaml $prometheusRule.additionalLabels | indent 8 }} + {{- end }} + spec: + groups: +{{ toYaml $prometheusRule.groups| indent 8 }} +{{- end }} +{{- else }} +{{- range .Values.additionalPrometheusRules }} + - apiVersion: monitoring.coreos.com/v1 + kind: PrometheusRule + metadata: + name: {{ template "kube-prometheus-stack.name" $ }}-{{ .name }} + namespace: {{ template "kube-prometheus-stack.namespace" $ }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }} +{{ include "kube-prometheus-stack.labels" $ | indent 8 }} + {{- if .additionalLabels }} +{{ toYaml .additionalLabels | indent 8 }} + {{- end }} + spec: + groups: +{{ toYaml .groups| indent 8 }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalScrapeConfigs.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalScrapeConfigs.yaml new file mode 100644 index 0000000000..ebdf766fde --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/additionalScrapeConfigs.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.prometheusSpec.additionalScrapeConfigs }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-scrape-confg + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- if .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations }} + annotations: +{{ toYaml .Values.prometheus.prometheusSpec.additionalPrometheusSecretsAnnotations | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus-scrape-confg +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: +{{- if eq ( typeOf .Values.prometheus.prometheusSpec.additionalScrapeConfigs ) "string" }} + additional-scrape-configs.yaml: {{ tpl .Values.prometheus.prometheusSpec.additionalScrapeConfigs $ | b64enc | quote }} +{{- else }} + additional-scrape-configs.yaml: {{ tpl (toYaml .Values.prometheus.prometheusSpec.additionalScrapeConfigs) $ | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ciliumnetworkpolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ciliumnetworkpolicy.yaml new file mode 100644 index 0000000000..74d61d7c13 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ciliumnetworkpolicy.yaml @@ -0,0 +1,27 @@ +{{- if and .Values.prometheus.networkPolicy.enabled (eq .Values.prometheus.networkPolicy.flavor "cilium") }} +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus + {{- include "kube-prometheus-stack.labels" . | nindent 4 }} +spec: + endpointSelector: + {{- if .Values.prometheus.networkPolicy.cilium.endpointSelector }} + {{- toYaml .Values.prometheus.networkPolicy.cilium.endpointSelector | nindent 4 }} + {{- else }} + matchExpressions: + - {key: app.kubernetes.io/name, operator: In, values: [prometheus]} + - {key: prometheus, operator: In, values: [{{ template "kube-prometheus-stack.prometheus.crname" . }}]} + {{- end }} + {{- if and .Values.prometheus.networkPolicy.cilium .Values.prometheus.networkPolicy.cilium.egress }} + egress: + {{ toYaml .Values.prometheus.networkPolicy.cilium.egress | nindent 4 }} + {{- end }} + {{- if and .Values.prometheus.networkPolicy.cilium .Values.prometheus.networkPolicy.cilium.ingress }} + ingress: + {{ toYaml .Values.prometheus.networkPolicy.cilium.ingress | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/clusterrole.yaml new file mode 100644 index 0000000000..eabdb24b95 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/clusterrole.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.prometheus.enabled .Values.global.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +rules: +# This permission are not in the kube-prometheus repo +# they're grabbed from https://github.com/prometheus/prometheus/blob/master/documentation/examples/rbac-setup.yml +- apiGroups: [""] + resources: + - nodes + - nodes/metrics + - services + - endpoints + - pods + verbs: ["get", "list", "watch"] +- apiGroups: + - "networking.k8s.io" + resources: + - ingresses + verbs: ["get", "list", "watch"] +- nonResourceURLs: ["/metrics", "/metrics/cadvisor"] + verbs: ["get"] +{{/* fix(#3338): add required rules to use node-exporter with the RBAC proxy */}} +{{- if and .Values.nodeExporter.enabled (index .Values "prometheus-node-exporter").kubeRBACProxy.enabled }} +- apiGroups: [ "" ] + resources: + - services/{{ include "prometheus-node-exporter.fullname" (index .Subcharts "prometheus-node-exporter") }} + verbs: [ "get", "list", "watch" ] +{{- end }} +{{- if and .Values.kubeStateMetrics.enabled (index .Values "kube-state-metrics").kubeRBACProxy.enabled }} +- apiGroups: [ "" ] + resources: + - services/{{ include "kube-state-metrics.fullname" (index .Subcharts "kube-state-metrics") }} + verbs: [ "get", "list", "watch" ] +{{- end }} +{{- if .Values.prometheus.additionalRulesForClusterRole }} +{{ toYaml .Values.prometheus.additionalRulesForClusterRole | indent 0 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/clusterrolebinding.yaml new file mode 100644 index 0000000000..9fc4f65da4 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/clusterrolebinding.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.prometheus.enabled .Values.global.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus +subjects: + - kind: ServiceAccount + name: {{ template "kube-prometheus-stack.prometheus.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- end }} + diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/csi-secret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/csi-secret.yaml new file mode 100644 index 0000000000..e05382f633 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/csi-secret.yaml @@ -0,0 +1,12 @@ +{{- if and .Values.prometheus.prometheusSpec.thanos .Values.prometheus.prometheusSpec.thanos.secretProviderClass }} +--- +apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 +kind: SecretProviderClass +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +spec: +{{ toYaml .Values.prometheus.prometheusSpec.thanos.secretProviderClass | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/extrasecret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/extrasecret.yaml new file mode 100644 index 0000000000..17f3478a46 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/extrasecret.yaml @@ -0,0 +1,20 @@ +{{- if .Values.prometheus.extraSecret.data -}} +{{- $secretName := printf "prometheus-%s-extra" (include "kube-prometheus-stack.fullname" . ) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default $secretName .Values.prometheus.extraSecret.name }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- if .Values.prometheus.extraSecret.annotations }} + annotations: +{{ toYaml .Values.prometheus.extraSecret.annotations | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus + app.kubernetes.io/component: prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: +{{- range $key, $val := .Values.prometheus.extraSecret.data }} + {{ $key }}: {{ $val | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingress.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingress.yaml new file mode 100644 index 0000000000..d2f6af5dd1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingress.yaml @@ -0,0 +1,77 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.ingress.enabled -}} + {{- $pathType := .Values.prometheus.ingress.pathType | default "ImplementationSpecific" -}} + {{- $serviceName := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus" -}} + {{- $servicePort := .Values.prometheus.ingress.servicePort | default .Values.prometheus.service.port -}} + {{- $routePrefix := list .Values.prometheus.prometheusSpec.routePrefix -}} + {{- $paths := .Values.prometheus.ingress.paths | default $routePrefix -}} + {{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}} + {{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}} +apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" . }} +kind: Ingress +metadata: +{{- if .Values.prometheus.ingress.annotations }} + annotations: + {{- tpl (toYaml .Values.prometheus.ingress.annotations) . | nindent 4 }} +{{- end }} + name: {{ $serviceName }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.prometheus.ingress.labels }} +{{ toYaml .Values.prometheus.ingress.labels | indent 4 }} +{{- end }} +spec: + {{- if $apiIsStable }} + {{- if .Values.prometheus.ingress.ingressClassName }} + ingressClassName: {{ .Values.prometheus.ingress.ingressClassName }} + {{- end }} + {{- end }} + rules: + {{- if .Values.prometheus.ingress.hosts }} + {{- range $host := .Values.prometheus.ingress.hosts }} + - host: {{ tpl $host $ }} + http: + paths: + {{- range $p := $paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end -}} + {{- end -}} + {{- else }} + - http: + paths: + {{- range $p := $paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end -}} + {{- end -}} + {{- if .Values.prometheus.ingress.tls }} + tls: +{{ tpl (toYaml .Values.prometheus.ingress.tls | indent 4) . }} + {{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingressThanosSidecar.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingressThanosSidecar.yaml new file mode 100644 index 0000000000..3f507cfa9f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingressThanosSidecar.yaml @@ -0,0 +1,77 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.thanosIngress.enabled }} +{{- $pathType := .Values.prometheus.thanosIngress.pathType | default "" }} +{{- $serviceName := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "thanos-discovery" }} +{{- $thanosPort := .Values.prometheus.thanosIngress.servicePort -}} +{{- $routePrefix := list .Values.prometheus.prometheusSpec.routePrefix }} +{{- $paths := .Values.prometheus.thanosIngress.paths | default $routePrefix -}} +{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}} +{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}} +apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" . }} +kind: Ingress +metadata: +{{- if .Values.prometheus.thanosIngress.annotations }} + annotations: + {{- tpl (toYaml .Values.prometheus.thanosIngress.annotations) . | nindent 4 }} +{{- end }} + name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-gateway + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.prometheus.thanosIngress.labels }} +{{ toYaml .Values.prometheus.thanosIngress.labels | indent 4 }} +{{- end }} +spec: + {{- if $apiIsStable }} + {{- if .Values.prometheus.thanosIngress.ingressClassName }} + ingressClassName: {{ .Values.prometheus.thanosIngress.ingressClassName }} + {{- end }} + {{- end }} + rules: + {{- if .Values.prometheus.thanosIngress.hosts }} + {{- range $host := .Values.prometheus.thanosIngress.hosts }} + - host: {{ tpl $host $ }} + http: + paths: + {{- range $p := $paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ $serviceName }} + port: + number: {{ $thanosPort }} + {{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $thanosPort }} + {{- end }} + {{- end -}} + {{- end -}} + {{- else }} + - http: + paths: + {{- range $p := $paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ $serviceName }} + port: + number: {{ $thanosPort }} + {{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $thanosPort }} + {{- end }} + {{- end -}} + {{- end -}} + {{- if .Values.prometheus.thanosIngress.tls }} + tls: +{{ tpl (toYaml .Values.prometheus.thanosIngress.tls | indent 4) . }} + {{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingressperreplica.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingressperreplica.yaml new file mode 100644 index 0000000000..1d76d135c8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/ingressperreplica.yaml @@ -0,0 +1,67 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.servicePerReplica.enabled .Values.prometheus.ingressPerReplica.enabled }} +{{- $pathType := .Values.prometheus.ingressPerReplica.pathType | default "" }} +{{- $count := .Values.prometheus.prometheusSpec.replicas | int -}} +{{- $servicePort := .Values.prometheus.servicePerReplica.port -}} +{{- $ingressValues := .Values.prometheus.ingressPerReplica -}} +{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}} +{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}} +apiVersion: v1 +kind: List +metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-ingressperreplica + namespace: {{ template "kube-prometheus-stack.namespace" $ }} +items: +{{ range $i, $e := until $count }} + - kind: Ingress + apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" $ }} + metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-{{ $i }} + namespace: {{ template "kube-prometheus-stack.namespace" $ }} + labels: + app: {{ include "kube-prometheus-stack.name" $ }}-prometheus + {{ include "kube-prometheus-stack.labels" $ | indent 8 }} + {{- if $ingressValues.labels }} +{{ toYaml $ingressValues.labels | indent 8 }} + {{- end }} + {{- if $ingressValues.annotations }} + annotations: + {{- tpl (toYaml $ingressValues.annotations) $ | nindent 8 }} + {{- end }} + spec: + {{- if $apiIsStable }} + {{- if $ingressValues.ingressClassName }} + ingressClassName: {{ $ingressValues.ingressClassName }} + {{- end }} + {{- end }} + rules: + - host: {{ $ingressValues.hostPrefix }}-{{ $i }}.{{ $ingressValues.hostDomain }} + http: + paths: + {{- range $p := $ingressValues.paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-{{ $i }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-{{ $i }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end -}} + {{- if or $ingressValues.tlsSecretName $ingressValues.tlsSecretPerReplica.enabled }} + tls: + - hosts: + - {{ $ingressValues.hostPrefix }}-{{ $i }}.{{ $ingressValues.hostDomain }} + {{- if $ingressValues.tlsSecretPerReplica.enabled }} + secretName: {{ $ingressValues.tlsSecretPerReplica.prefix }}-{{ $i }} + {{- else }} + secretName: {{ $ingressValues.tlsSecretName }} + {{- end }} + {{- end }} +{{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/networkpolicy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/networkpolicy.yaml new file mode 100644 index 0000000000..1296a79063 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/networkpolicy.yaml @@ -0,0 +1,34 @@ +{{- if and .Values.prometheus.networkPolicy.enabled (eq .Values.prometheus.networkPolicy.flavor "kubernetes") }} +apiVersion: {{ template "kube-prometheus-stack.prometheus.networkPolicy.apiVersion" . }} +kind: NetworkPolicy +metadata: + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus + {{- include "kube-prometheus-stack.labels" . | nindent 4 }} + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + namespace: {{ template "kube-prometheus-stack.namespace" . }} +spec: + {{- if .Values.prometheus.networkPolicy.egress }} + egress: + {{- toYaml .Values.prometheus.networkPolicy.egress | nindent 4 }} + {{- end }} + {{- if .Values.prometheus.networkPolicy.ingress }} + ingress: + {{- toYaml .Values.prometheus.networkPolicy.ingress | nindent 4 }} + {{- end }} + policyTypes: + - Egress + - Ingress + podSelector: + {{- if .Values.prometheus.networkPolicy.podSelector }} + {{- toYaml .Values.prometheus.networkPolicy.podSelector | nindent 4 }} + {{- else }} + matchLabels: + {{- if .Values.prometheus.agentMode }} + app.kubernetes.io/name: prometheus-agent + {{- else }} + app.kubernetes.io/name: prometheus + {{- end }} + operator.prometheus.io/name: {{ template "kube-prometheus-stack.prometheus.crname" . }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/nginx-config.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/nginx-config.yaml new file mode 100644 index 0000000000..e4d91f9a9e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/nginx-config.yaml @@ -0,0 +1,68 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: prometheus-nginx-proxy-config + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.prometheus.annotations }} + annotations: +{{ toYaml .Values.prometheus.annotations | indent 4 }} +{{- end }} +data: + nginx.conf: |- + worker_processes auto; + error_log /dev/stdout warn; + pid /var/cache/nginx/nginx.pid; + + events { + worker_connections 1024; + } + + http { + include /etc/nginx/mime.types; + log_format main '[$time_local - $status] $remote_addr - $remote_user $request ($http_referer)'; + + proxy_connect_timeout 10; + proxy_read_timeout 180; + proxy_send_timeout 5; + proxy_buffering off; + proxy_cache_path /var/cache/nginx/cache levels=1:2 keys_zone=my_zone:100m inactive=1d max_size=10g; + + server { + listen 8081; + access_log off; + + gzip on; + gzip_min_length 1k; + gzip_comp_level 2; + gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript image/jpeg image/gif image/png; + gzip_vary on; + gzip_disable "MSIE [1-6]\."; + + proxy_set_header Host $host; + + location / { + proxy_cache my_zone; + proxy_cache_valid 200 302 1d; + proxy_cache_valid 301 30d; + proxy_cache_valid any 5m; + proxy_cache_bypass $http_cache_control; + add_header X-Proxy-Cache $upstream_cache_status; + add_header Cache-Control "public"; + + proxy_pass http://localhost:9090/; + + sub_filter_once off; + sub_filter 'var PATH_PREFIX = "";' 'var PATH_PREFIX = ".";'; + + if ($request_filename ~ .*\.(?:js|css|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$) { + expires 90d; + } + + rewrite ^/k8s/clusters/.*/proxy(.*) /$1 break; + + } + } + } diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/podDisruptionBudget.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/podDisruptionBudget.yaml new file mode 100644 index 0000000000..48f3f1f5a6 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/podDisruptionBudget.yaml @@ -0,0 +1,25 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.podDisruptionBudget.enabled }} +apiVersion: {{ include "kube-prometheus-stack.pdb.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + {{- if .Values.prometheus.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.prometheus.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.prometheus.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.prometheus.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + {{- if .Values.prometheus.agentMode }} + app.kubernetes.io/name: prometheus-agent + {{- else }} + app.kubernetes.io/name: prometheus + {{- end }} + operator.prometheus.io/name: {{ template "kube-prometheus-stack.prometheus.crname" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/podmonitors.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/podmonitors.yaml new file mode 100644 index 0000000000..4e748c23b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/podmonitors.yaml @@ -0,0 +1,38 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.additionalPodMonitors }} +apiVersion: v1 +kind: List +items: +{{- range .Values.prometheus.additionalPodMonitors }} + - apiVersion: monitoring.coreos.com/v1 + kind: PodMonitor + metadata: + name: {{ .name }} + namespace: {{ template "kube-prometheus-stack.namespace" $ }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-prometheus +{{ include "kube-prometheus-stack.labels" $ | indent 8 }} + {{- if .additionalLabels }} +{{ toYaml .additionalLabels | indent 8 }} + {{- end }} + spec: + {{- include "servicemonitor.scrapeLimits" . | nindent 6 }} + podMetricsEndpoints: +{{ toYaml .podMetricsEndpoints | indent 8 }} + {{- if .jobLabel }} + jobLabel: {{ .jobLabel }} + {{- end }} + {{- if .namespaceSelector }} + namespaceSelector: +{{ toYaml .namespaceSelector | indent 8 }} + {{- end }} + selector: +{{ toYaml .selector | indent 8 }} + {{- if .podTargetLabels }} + podTargetLabels: +{{ toYaml .podTargetLabels | indent 8 }} + {{- end }} + {{- if .sampleLimit }} + sampleLimit: {{ .sampleLimit }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/prometheus.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/prometheus.yaml new file mode 100644 index 0000000000..e668b40a9f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/prometheus.yaml @@ -0,0 +1,481 @@ +{{- if .Values.prometheus.enabled }} +{{- if .Values.prometheus.agentMode }} +apiVersion: monitoring.coreos.com/v1alpha1 +kind: PrometheusAgent +{{- else }} +apiVersion: monitoring.coreos.com/v1 +kind: Prometheus +{{- end }} +metadata: + name: {{ template "kube-prometheus-stack.prometheus.crname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.prometheus.annotations }} + annotations: +{{ toYaml .Values.prometheus.annotations | indent 4 }} +{{- end }} +spec: + automountServiceAccountToken: {{ .Values.prometheus.prometheusSpec.automountServiceAccountToken }} +{{- if and (not .Values.prometheus.agentMode) (or .Values.prometheus.prometheusSpec.alertingEndpoints .Values.alertmanager.enabled) }} + alerting: + alertmanagers: +{{- if .Values.prometheus.prometheusSpec.alertingEndpoints }} +{{ toYaml .Values.prometheus.prometheusSpec.alertingEndpoints | indent 6 }} +{{- else if .Values.alertmanager.enabled }} + - namespace: {{ template "kube-prometheus-stack.namespace" . }} + name: {{ template "kube-prometheus-stack.fullname" . }}-alertmanager + port: {{ .Values.alertmanager.alertmanagerSpec.portName }} + {{- if .Values.alertmanager.alertmanagerSpec.routePrefix }} + pathPrefix: "{{ .Values.alertmanager.alertmanagerSpec.routePrefix }}" + {{- end }} + {{- if .Values.alertmanager.alertmanagerSpec.scheme }} + scheme: {{ .Values.alertmanager.alertmanagerSpec.scheme }} + {{- end }} + {{- if .Values.alertmanager.alertmanagerSpec.tlsConfig }} + tlsConfig: +{{ toYaml .Values.alertmanager.alertmanagerSpec.tlsConfig | indent 10 }} + {{- end }} + apiVersion: {{ .Values.alertmanager.apiVersion }} +{{- end }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.apiserverConfig }} + apiserverConfig: +{{ toYaml .Values.prometheus.prometheusSpec.apiserverConfig | indent 4}} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.image }} + {{- $registry := include "monitoring_registry" . | default .Values.prometheus.prometheusSpec.image.registry -}} + {{- if and .Values.prometheus.prometheusSpec.image.tag .Values.prometheus.prometheusSpec.image.sha }} + image: "{{ $registry }}/{{ .Values.prometheus.prometheusSpec.image.repository }}:{{ .Values.prometheus.prometheusSpec.image.tag }}@sha256:{{ .Values.prometheus.prometheusSpec.image.sha }}" + {{- else if .Values.prometheus.prometheusSpec.image.sha }} + image: "{{ $registry }}/{{ .Values.prometheus.prometheusSpec.image.repository }}@sha256:{{ .Values.prometheus.prometheusSpec.image.sha }}" + {{- else if .Values.prometheus.prometheusSpec.image.tag }} + image: "{{ $registry }}/{{ .Values.prometheus.prometheusSpec.image.repository }}:{{ .Values.prometheus.prometheusSpec.image.tag }}" + {{- else }} + image: "{{ $registry }}/{{ .Values.prometheus.prometheusSpec.image.repository }}" + {{- end }} + version: {{ default .Values.prometheus.prometheusSpec.image.tag .Values.prometheus.prometheusSpec.version }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.additionalArgs }} + additionalArgs: +{{ toYaml .Values.prometheus.prometheusSpec.additionalArgs | indent 4}} +{{- end -}} +{{- if .Values.prometheus.prometheusSpec.externalLabels }} + externalLabels: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.externalLabels | indent 4) . }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.prometheusExternalLabelNameClear }} + prometheusExternalLabelName: "" +{{- else if .Values.prometheus.prometheusSpec.prometheusExternalLabelName }} + prometheusExternalLabelName: "{{ .Values.prometheus.prometheusSpec.prometheusExternalLabelName }}" +{{- end }} +{{- if .Values.prometheus.prometheusSpec.replicaExternalLabelNameClear }} + replicaExternalLabelName: "" +{{- else if .Values.prometheus.prometheusSpec.replicaExternalLabelName }} + replicaExternalLabelName: "{{ .Values.prometheus.prometheusSpec.replicaExternalLabelName }}" +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enableRemoteWriteReceiver }} + enableRemoteWriteReceiver: {{ .Values.prometheus.prometheusSpec.enableRemoteWriteReceiver }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.externalUrl }} + externalUrl: "{{ tpl .Values.prometheus.prometheusSpec.externalUrl . }}" +{{- else if and .Values.prometheus.ingress.enabled .Values.prometheus.ingress.hosts }} + externalUrl: "http://{{ tpl (index .Values.prometheus.ingress.hosts 0) . }}{{ .Values.prometheus.prometheusSpec.routePrefix }}" +{{- else if not (or (kindIs "invalid" .Values.global.cattle.url) (kindIs "invalid" .Values.global.cattle.clusterId)) }} + externalUrl: "{{ .Values.global.cattle.url }}/k8s/clusters/{{ .Values.global.cattle.clusterId }}/api/v1/namespaces/{{ template "kube-prometheus-stack.namespace" . }}/services/http:{{ template "kube-prometheus-stack.fullname" . }}-prometheus:{{ .Values.prometheus.service.port }}/proxy" +{{- else }} + externalUrl: http://{{ template "kube-prometheus-stack.fullname" . }}-prometheus.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.prometheus.service.port }} +{{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 4 }} +{{- if .Values.prometheus.prometheusSpec.nodeSelector }} +{{ toYaml .Values.prometheus.prometheusSpec.nodeSelector | indent 4 }} +{{- end }} + paused: {{ .Values.prometheus.prometheusSpec.paused }} + replicas: {{ .Values.prometheus.prometheusSpec.replicas }} + shards: {{ .Values.prometheus.prometheusSpec.shards }} + logLevel: {{ .Values.prometheus.prometheusSpec.logLevel }} + logFormat: {{ .Values.prometheus.prometheusSpec.logFormat }} + listenLocal: {{ .Values.prometheus.prometheusSpec.listenLocal }} +{{- if not .Values.prometheus.agentMode }} + enableAdminAPI: {{ .Values.prometheus.prometheusSpec.enableAdminAPI }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.web }} + web: +{{ toYaml .Values.prometheus.prometheusSpec.web | indent 4 }} +{{- end }} +{{- if and (not .Values.prometheus.agentMode) .Values.prometheus.prometheusSpec.exemplars }} + exemplars: + {{- toYaml .Values.prometheus.prometheusSpec.exemplars | nindent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enableFeatures }} + enableFeatures: +{{- range $enableFeatures := .Values.prometheus.prometheusSpec.enableFeatures }} + - {{ tpl $enableFeatures $ }} +{{- end }} +{{- end }} +{{- with .Values.prometheus.prometheusSpec.scrapeClasses }} + scrapeClasses: + {{- tpl (toYaml . | nindent 4) $ }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.scrapeInterval }} + scrapeInterval: {{ .Values.prometheus.prometheusSpec.scrapeInterval }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.scrapeTimeout }} + scrapeTimeout: {{ .Values.prometheus.prometheusSpec.scrapeTimeout }} +{{- end }} +{{- if and (not .Values.prometheus.agentMode) .Values.prometheus.prometheusSpec.evaluationInterval }} + evaluationInterval: {{ .Values.prometheus.prometheusSpec.evaluationInterval }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.resources }} + resources: +{{ toYaml .Values.prometheus.prometheusSpec.resources | indent 4 }} +{{- end }} +{{- if not .Values.prometheus.agentMode }} + retention: {{ .Values.prometheus.prometheusSpec.retention | quote }} +{{- if .Values.prometheus.prometheusSpec.retentionSize }} + retentionSize: {{ .Values.prometheus.prometheusSpec.retentionSize | quote }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.tsdb }} + tsdb: + {{- if .Values.prometheus.prometheusSpec.tsdb.outOfOrderTimeWindow }} + outOfOrderTimeWindow: {{ .Values.prometheus.prometheusSpec.tsdb.outOfOrderTimeWindow }} + {{- end }} +{{- end }} +{{- end }} +{{- if eq .Values.prometheus.prometheusSpec.walCompression false }} + walCompression: false +{{ else }} + walCompression: true +{{- end }} +{{- if .Values.prometheus.prometheusSpec.routePrefix }} + routePrefix: {{ .Values.prometheus.prometheusSpec.routePrefix | quote }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.secrets }} + secrets: +{{ toYaml .Values.prometheus.prometheusSpec.secrets | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.configMaps }} + configMaps: +{{ toYaml .Values.prometheus.prometheusSpec.configMaps | indent 4 }} +{{- end }} + serviceAccountName: {{ template "kube-prometheus-stack.prometheus.serviceAccountName" . }} +{{- if .Values.prometheus.prometheusSpec.serviceMonitorSelector }} + serviceMonitorSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.serviceMonitorSelector | indent 4) . }} +{{ else if .Values.prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues }} + serviceMonitorSelector: + matchLabels: + release: {{ $.Release.Name | quote }} +{{ else }} + serviceMonitorSelector: {} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.serviceMonitorNamespaceSelector }} + serviceMonitorNamespaceSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.serviceMonitorNamespaceSelector | indent 4) . }} +{{ else }} + serviceMonitorNamespaceSelector: {} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.podMonitorSelector }} + podMonitorSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.podMonitorSelector | indent 4) . }} +{{ else if .Values.prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues }} + podMonitorSelector: + matchLabels: + release: {{ $.Release.Name | quote }} +{{ else }} + podMonitorSelector: {} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.podMonitorNamespaceSelector }} + podMonitorNamespaceSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.podMonitorNamespaceSelector | indent 4) . }} +{{ else }} + podMonitorNamespaceSelector: {} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.probeSelector }} + probeSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.probeSelector | indent 4) . }} +{{ else if .Values.prometheus.prometheusSpec.probeSelectorNilUsesHelmValues }} + probeSelector: + matchLabels: + release: {{ $.Release.Name | quote }} +{{ else }} + probeSelector: {} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.probeNamespaceSelector }} + probeNamespaceSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.probeNamespaceSelector | indent 4) . }} +{{ else }} + probeNamespaceSelector: {} +{{- end }} +{{- if and (not .Values.prometheus.agentMode) (or .Values.prometheus.prometheusSpec.remoteRead .Values.prometheus.prometheusSpec.additionalRemoteRead) }} + remoteRead: +{{- if .Values.prometheus.prometheusSpec.remoteRead }} +{{ tpl (toYaml .Values.prometheus.prometheusSpec.remoteRead | indent 4) . }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.additionalRemoteRead }} +{{ toYaml .Values.prometheus.prometheusSpec.additionalRemoteRead | indent 4 }} +{{- end }} +{{- end }} +{{- if (or .Values.prometheus.prometheusSpec.remoteWrite .Values.prometheus.prometheusSpec.additionalRemoteWrite) }} + remoteWrite: +{{- if .Values.prometheus.prometheusSpec.remoteWrite }} +{{ tpl (toYaml .Values.prometheus.prometheusSpec.remoteWrite | indent 4) . }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.additionalRemoteWrite }} +{{ toYaml .Values.prometheus.prometheusSpec.additionalRemoteWrite | indent 4 }} +{{- end }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.securityContext }} + securityContext: +{{ toYaml .Values.prometheus.prometheusSpec.securityContext | indent 4 }} +{{- end }} +{{- if not .Values.prometheus.agentMode }} +{{- if .Values.prometheus.prometheusSpec.ruleNamespaceSelector }} + ruleNamespaceSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.ruleNamespaceSelector | indent 4) . }} +{{ else }} + ruleNamespaceSelector: {} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.ruleSelector }} + ruleSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.ruleSelector | indent 4) . }} +{{- else if .Values.prometheus.prometheusSpec.ruleSelectorNilUsesHelmValues }} + ruleSelector: + matchLabels: + release: {{ $.Release.Name | quote }} +{{ else }} + ruleSelector: {} +{{- end }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.scrapeConfigSelector }} + scrapeConfigSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.scrapeConfigSelector | indent 4) . }} +{{ else if .Values.prometheus.prometheusSpec.scrapeConfigSelectorNilUsesHelmValues }} + scrapeConfigSelector: + matchLabels: + release: {{ $.Release.Name | quote }} +{{ else }} + scrapeConfigSelector: {} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.scrapeConfigNamespaceSelector }} + scrapeConfigNamespaceSelector: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.scrapeConfigNamespaceSelector | indent 4) . }} +{{ else }} + scrapeConfigNamespaceSelector: {} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.storageSpec }} + storage: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.storageSpec | indent 4) . }} +{{- end }} +{{- with .Values.prometheus.prometheusSpec.persistentVolumeClaimRetentionPolicy }} + persistentVolumeClaimRetentionPolicy: + {{- toYaml . | nindent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.podMetadata }} + podMetadata: +{{ tpl (toYaml .Values.prometheus.prometheusSpec.podMetadata | indent 4) . }} +{{- end }} +{{- if and (not .Values.prometheus.agentMode) .Values.prometheus.prometheusSpec.query }} + query: +{{ toYaml .Values.prometheus.prometheusSpec.query | indent 4}} +{{- end }} +{{- if or .Values.prometheus.prometheusSpec.podAntiAffinity .Values.prometheus.prometheusSpec.affinity }} + affinity: +{{- if .Values.prometheus.prometheusSpec.affinity }} +{{ toYaml .Values.prometheus.prometheusSpec.affinity | indent 4 }} +{{- end }} +{{- if eq .Values.prometheus.prometheusSpec.podAntiAffinity "hard" }} + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: {{ .Values.prometheus.prometheusSpec.podAntiAffinityTopologyKey }} + labelSelector: + matchExpressions: + - {key: app.kubernetes.io/name, operator: In, values: [prometheus]} + - {key: prometheus, operator: In, values: [{{ template "kube-prometheus-stack.prometheus.crname" . }}]} +{{- else if eq .Values.prometheus.prometheusSpec.podAntiAffinity "soft" }} + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: {{ .Values.prometheus.prometheusSpec.podAntiAffinityTopologyKey }} + labelSelector: + matchExpressions: + - {key: app.kubernetes.io/name, operator: In, values: [prometheus]} + - {key: prometheus, operator: In, values: [{{ template "kube-prometheus-stack.prometheus.crname" . }}]} +{{- end }} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 4 }} +{{- if .Values.prometheus.prometheusSpec.tolerations }} +{{ toYaml .Values.prometheus.prometheusSpec.tolerations | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.prometheus.prometheusSpec.topologySpreadConstraints | indent 4 }} +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.additionalScrapeConfigs }} + additionalScrapeConfigs: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-scrape-confg + key: additional-scrape-configs.yaml +{{- end }} +{{- if .Values.prometheus.prometheusSpec.additionalScrapeConfigsSecret.enabled }} + additionalScrapeConfigs: + name: {{ .Values.prometheus.prometheusSpec.additionalScrapeConfigsSecret.name }} + key: {{ .Values.prometheus.prometheusSpec.additionalScrapeConfigsSecret.key }} +{{- end }} +{{- if not .Values.prometheus.agentMode }} +{{- if or .Values.prometheus.prometheusSpec.additionalAlertManagerConfigs .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret }} + additionalAlertManagerConfigs: +{{- if .Values.prometheus.prometheusSpec.additionalAlertManagerConfigs }} + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-am-confg + key: additional-alertmanager-configs.yaml +{{- end }} +{{- if .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret }} + name: {{ .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret.name }} + key: {{ .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret.key }} + {{- if hasKey .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret "optional" }} + optional: {{ .Values.prometheus.prometheusSpec.additionalAlertManagerConfigsSecret.optional }} + {{- end }} +{{- end }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigs }} + additionalAlertRelabelConfigs: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-am-relabel-confg + key: additional-alert-relabel-configs.yaml +{{- end }} +{{- if .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigsSecret }} + additionalAlertRelabelConfigs: + name: {{ .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigsSecret.name }} + key: {{ .Values.prometheus.prometheusSpec.additionalAlertRelabelConfigsSecret.key }} +{{- end }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.containers }} + containers: +{{ tpl .Values.prometheus.prometheusSpec.containers $ | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.initContainers }} + initContainers: +{{ toYaml .Values.prometheus.prometheusSpec.initContainers | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.priorityClassName }} + priorityClassName: {{ .Values.prometheus.prometheusSpec.priorityClassName }} +{{- end }} +{{- if not .Values.prometheus.agentMode }} +{{- if .Values.prometheus.prometheusSpec.thanos }} + thanos: +{{- with (omit .Values.prometheus.prometheusSpec.thanos "objectStorageConfig")}} +{{ toYaml . | indent 4 }} +{{- end }} +{{- if ((.Values.prometheus.prometheusSpec.thanos.objectStorageConfig).existingSecret) }} + objectStorageConfig: + key: "{{.Values.prometheus.prometheusSpec.thanos.objectStorageConfig.existingSecret.key }}" + name: "{{.Values.prometheus.prometheusSpec.thanos.objectStorageConfig.existingSecret.name }}" +{{- else if ((.Values.prometheus.prometheusSpec.thanos.objectStorageConfig).secret) }} + objectStorageConfig: + key: object-storage-configs.yaml + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus +{{- end }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.disableCompaction }} + disableCompaction: {{ .Values.prometheus.prometheusSpec.disableCompaction }} +{{- end }} +{{- end }} + portName: {{ .Values.prometheus.prometheusSpec.portName }} +{{- if .Values.prometheus.prometheusSpec.volumes }} + volumes: +{{ toYaml .Values.prometheus.prometheusSpec.volumes | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.volumeMounts }} + volumeMounts: +{{ toYaml .Values.prometheus.prometheusSpec.volumeMounts | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.arbitraryFSAccessThroughSMs }} + arbitraryFSAccessThroughSMs: +{{ toYaml .Values.prometheus.prometheusSpec.arbitraryFSAccessThroughSMs | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.overrideHonorLabels }} + overrideHonorLabels: {{ .Values.prometheus.prometheusSpec.overrideHonorLabels }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.overrideHonorTimestamps }} + overrideHonorTimestamps: {{ .Values.prometheus.prometheusSpec.overrideHonorTimestamps }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} + ignoreNamespaceSelectors: {{ .Values.prometheus.prometheusSpec.ignoreNamespaceSelectors }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enforcedNamespaceLabel }} + enforcedNamespaceLabel: {{ .Values.prometheus.prometheusSpec.enforcedNamespaceLabel }} +{{- $prometheusDefaultRulesExcludedFromEnforce := (include "rules.names" .) | fromYaml }} +{{- if not .Values.prometheus.agentMode }} + prometheusRulesExcludedFromEnforce: +{{- range $prometheusDefaultRulesExcludedFromEnforce.rules }} + - ruleNamespace: "{{ template "kube-prometheus-stack.namespace" $ }}" + ruleName: "{{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) . | trunc 63 | trimSuffix "-" }}" +{{- end }} +{{- if .Values.prometheus.prometheusSpec.prometheusRulesExcludedFromEnforce }} +{{ toYaml .Values.prometheus.prometheusSpec.prometheusRulesExcludedFromEnforce | indent 4 }} +{{- end }} +{{- end }} + excludedFromEnforcement: +{{- range $prometheusDefaultRulesExcludedFromEnforce.rules }} + - group: monitoring.coreos.com + resource: prometheusrules + namespace: "{{ template "kube-prometheus-stack.namespace" $ }}" + name: "{{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) . | trunc 63 | trimSuffix "-" }}" +{{- end }} +{{- if .Values.prometheus.prometheusSpec.excludedFromEnforcement }} +{{ tpl (toYaml .Values.prometheus.prometheusSpec.excludedFromEnforcement | indent 4) . }} +{{- end }} +{{- end }} +{{- if and (not .Values.prometheus.agentMode) .Values.prometheus.prometheusSpec.queryLogFile }} + queryLogFile: {{ .Values.prometheus.prometheusSpec.queryLogFile }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.sampleLimit }} + sampleLimit: {{ .Values.prometheus.prometheusSpec.sampleLimit }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enforcedKeepDroppedTargets }} + enforcedKeepDroppedTargets: {{ .Values.prometheus.prometheusSpec.enforcedKeepDroppedTargets }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enforcedSampleLimit }} + enforcedSampleLimit: {{ .Values.prometheus.prometheusSpec.enforcedSampleLimit }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enforcedTargetLimit }} + enforcedTargetLimit: {{ .Values.prometheus.prometheusSpec.enforcedTargetLimit }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enforcedLabelLimit }} + enforcedLabelLimit: {{ .Values.prometheus.prometheusSpec.enforcedLabelLimit }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enforcedLabelNameLengthLimit }} + enforcedLabelNameLengthLimit: {{ .Values.prometheus.prometheusSpec.enforcedLabelNameLengthLimit }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.enforcedLabelValueLengthLimit}} + enforcedLabelValueLengthLimit: {{ .Values.prometheus.prometheusSpec.enforcedLabelValueLengthLimit }} +{{- end }} +{{- if and (not .Values.prometheus.agentMode) .Values.prometheus.prometheusSpec.allowOverlappingBlocks }} + allowOverlappingBlocks: {{ .Values.prometheus.prometheusSpec.allowOverlappingBlocks }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.minReadySeconds }} + minReadySeconds: {{ .Values.prometheus.prometheusSpec.minReadySeconds }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.maximumStartupDurationSeconds }} + maximumStartupDurationSeconds: {{ .Values.prometheus.prometheusSpec.maximumStartupDurationSeconds }} +{{- end }} + hostNetwork: {{ .Values.prometheus.prometheusSpec.hostNetwork }} +{{- if .Values.prometheus.prometheusSpec.hostAliases }} + hostAliases: +{{ toYaml .Values.prometheus.prometheusSpec.hostAliases | indent 4 }} +{{- end }} +{{- if .Values.prometheus.prometheusSpec.tracingConfig }} + tracingConfig: +{{ toYaml .Values.prometheus.prometheusSpec.tracingConfig | indent 4 }} +{{- end }} +{{- with .Values.prometheus.prometheusSpec.additionalConfig }} + {{- tpl (toYaml .) $ | nindent 2 }} +{{- end }} +{{- with .Values.prometheus.prometheusSpec.additionalConfigString }} + {{- tpl . $ | nindent 2 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp-clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp-clusterrole.yaml new file mode 100644 index 0000000000..872feb6066 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp-clusterrole.yaml @@ -0,0 +1,22 @@ +{{- if and .Values.prometheus.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-psp + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +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-prometheus-stack.fullname" . }}-prometheus +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp-clusterrolebinding.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp-clusterrolebinding.yaml new file mode 100644 index 0000000000..50e3617704 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp-clusterrolebinding.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.prometheus.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-psp + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus-psp +subjects: + - kind: ServiceAccount + name: {{ template "kube-prometheus-stack.prometheus.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp.yaml new file mode 100644 index 0000000000..b53808daa5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/psp.yaml @@ -0,0 +1,58 @@ +{{- if and .Values.prometheus.enabled .Values.global.rbac.create .Values.global.rbac.pspEnabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodSecurityPolicy" }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{- if .Values.global.rbac.pspAnnotations }} + annotations: +{{ toYaml .Values.global.rbac.pspAnnotations | indent 4 }} +{{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + privileged: false + # Allow core volume types. + volumes: + - 'configMap' + - 'emptyDir' + - 'projected' + - 'secret' + - 'downwardAPI' + - 'persistentVolumeClaim' +{{- if .Values.prometheus.podSecurityPolicy.volumes }} +{{ toYaml .Values.prometheus.podSecurityPolicy.volumes | indent 4 }} +{{- end }} + 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: + # Allow adding the root group. + - min: 0 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Allow adding the root group. + - min: 0 + max: 65535 + readOnlyRootFilesystem: false +{{- if .Values.prometheus.podSecurityPolicy.allowedCapabilities }} + allowedCapabilities: +{{ toYaml .Values.prometheus.podSecurityPolicy.allowedCapabilities | indent 4 }} +{{- end }} +{{- if .Values.prometheus.podSecurityPolicy.allowedHostPaths }} + allowedHostPaths: +{{ toYaml .Values.prometheus.podSecurityPolicy.allowedHostPaths | indent 4 }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/alertmanager.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/alertmanager.rules.yaml new file mode 100644 index 0000000000..2d432c8f3a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/alertmanager.rules.yaml @@ -0,0 +1,305 @@ +{{- /* +Generated from 'alertmanager.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.alertmanager }} +{{- $alertmanagerJob := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "alertmanager" }} +{{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }} +{{- if and .Values.alertmanager.enabled .Values.alertmanager.serviceMonitor.selfMonitor }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "alertmanager.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: alertmanager.rules + rules: +{{- if not (.Values.defaultRules.disabled.AlertmanagerFailedReload | default false) }} + - alert: AlertmanagerFailedReload + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager | indent 8 }} +{{- end }} + description: Configuration has failed to load for {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod{{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerfailedreload + summary: Reloading an Alertmanager configuration has failed. + expr: |- + # Without max_over_time, failed scrapes could create false negatives, see + # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details. + max_over_time(alertmanager_config_last_reload_successful{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m]) == 0 + for: {{ dig "AlertmanagerFailedReload" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "AlertmanagerFailedReload" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.AlertmanagerMembersInconsistent | default false) }} + - alert: AlertmanagerMembersInconsistent + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager | indent 8 }} +{{- end }} + description: Alertmanager {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod{{`}}`}} has only found {{`{{`}} $value {{`}}`}} members of the {{`{{`}}$labels.job{{`}}`}} cluster. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagermembersinconsistent + summary: A member of an Alertmanager cluster has not found all other cluster members. + expr: |- + # Without max_over_time, failed scrapes could create false negatives, see + # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details. + max_over_time(alertmanager_cluster_members{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m]) + < on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service,cluster) group_left + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service,cluster) (max_over_time(alertmanager_cluster_members{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m])) + for: {{ dig "AlertmanagerMembersInconsistent" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "AlertmanagerMembersInconsistent" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.AlertmanagerFailedToSendAlerts | default false) }} + - alert: AlertmanagerFailedToSendAlerts + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager | indent 8 }} +{{- end }} + description: Alertmanager {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod{{`}}`}} failed to send {{`{{`}} $value | humanizePercentage {{`}}`}} of notifications to {{`{{`}} $labels.integration {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerfailedtosendalerts + summary: An Alertmanager instance failed to send notifications. + expr: |- + ( + rate(alertmanager_notifications_failed_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m]) + / + ignoring (reason) group_left rate(alertmanager_notifications_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m]) + ) + > 0.01 + for: {{ dig "AlertmanagerFailedToSendAlerts" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "AlertmanagerFailedToSendAlerts" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.AlertmanagerClusterFailedToSendAlerts | default false) }} + - alert: AlertmanagerClusterFailedToSendAlerts + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager | indent 8 }} +{{- end }} + description: The minimum notification failure rate to {{`{{`}} $labels.integration {{`}}`}} sent from any instance in the {{`{{`}}$labels.job{{`}}`}} cluster is {{`{{`}} $value | humanizePercentage {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerclusterfailedtosendalerts + summary: All Alertmanager instances in a cluster failed to send notifications to a critical integration. + expr: |- + min by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service, integration) ( + rate(alertmanager_notifications_failed_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}", integration=~`.*`}[5m]) + / + ignoring (reason) group_left rate(alertmanager_notifications_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}", integration=~`.*`}[5m]) + ) + > 0.01 + for: {{ dig "AlertmanagerClusterFailedToSendAlerts" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "AlertmanagerClusterFailedToSendAlerts" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.AlertmanagerClusterFailedToSendAlerts | default false) }} + - alert: AlertmanagerClusterFailedToSendAlerts + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager | indent 8 }} +{{- end }} + description: The minimum notification failure rate to {{`{{`}} $labels.integration {{`}}`}} sent from any instance in the {{`{{`}}$labels.job{{`}}`}} cluster is {{`{{`}} $value | humanizePercentage {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerclusterfailedtosendalerts + summary: All Alertmanager instances in a cluster failed to send notifications to a non-critical integration. + expr: |- + min by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service, integration) ( + rate(alertmanager_notifications_failed_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}", integration!~`.*`}[5m]) + / + ignoring (reason) group_left rate(alertmanager_notifications_total{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}", integration!~`.*`}[5m]) + ) + > 0.01 + for: {{ dig "AlertmanagerClusterFailedToSendAlerts" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "AlertmanagerClusterFailedToSendAlerts" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.AlertmanagerConfigInconsistent | default false) }} + - alert: AlertmanagerConfigInconsistent + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager | indent 8 }} +{{- end }} + description: Alertmanager instances within the {{`{{`}}$labels.job{{`}}`}} cluster have different configurations. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerconfiginconsistent + summary: Alertmanager instances within the same cluster have different configurations. + expr: |- + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service,cluster) ( + count_values by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service,cluster) ("config_hash", alertmanager_config_hash{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}) + ) + != 1 + for: {{ dig "AlertmanagerConfigInconsistent" "for" "20m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "AlertmanagerConfigInconsistent" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.AlertmanagerClusterDown | default false) }} + - alert: AlertmanagerClusterDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager | indent 8 }} +{{- end }} + description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of Alertmanager instances within the {{`{{`}}$labels.job{{`}}`}} cluster have been up for less than half of the last 5m.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerclusterdown + summary: Half or more of the Alertmanager instances within the same cluster are down. + expr: |- + ( + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service,cluster) ( + avg_over_time(up{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[5m]) < 0.5 + ) + / + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service,cluster) ( + up{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"} + ) + ) + >= 0.5 + for: {{ dig "AlertmanagerClusterDown" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "AlertmanagerClusterDown" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.AlertmanagerClusterCrashlooping | default false) }} + - alert: AlertmanagerClusterCrashlooping + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.alertmanager | indent 8 }} +{{- end }} + description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of Alertmanager instances within the {{`{{`}}$labels.job{{`}}`}} cluster have restarted at least 5 times in the last 10m.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/alertmanager/alertmanagerclustercrashlooping + summary: Half or more of the Alertmanager instances within the same cluster are crashlooping. + expr: |- + ( + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service,cluster) ( + changes(process_start_time_seconds{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"}[10m]) > 4 + ) + / + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace,service,cluster) ( + up{job="{{ $alertmanagerJob }}",namespace="{{ $namespace }}"} + ) + ) + >= 0.5 + for: {{ dig "AlertmanagerClusterCrashlooping" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "AlertmanagerClusterCrashlooping" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.alertmanager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/config-reloaders.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/config-reloaders.yaml new file mode 100644 index 0000000000..9f554c022f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/config-reloaders.yaml @@ -0,0 +1,57 @@ +{{- /* +Generated from 'config-reloaders' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.configReloaders }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "config-reloaders" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: config-reloaders + rules: +{{- if not (.Values.defaultRules.disabled.ConfigReloaderSidecarErrors | default false) }} + - alert: ConfigReloaderSidecarErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.configReloaders }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.configReloaders | indent 8 }} +{{- end }} + description: 'Errors encountered while the {{`{{`}}$labels.pod{{`}}`}} config-reloader sidecar attempts to sync config in {{`{{`}}$labels.namespace{{`}}`}} namespace. + + As a result, configuration for service running in {{`{{`}}$labels.pod{{`}}`}} may be stale and cannot be updated anymore.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/configreloadersidecarerrors + summary: config-reloader sidecar has not had a successful reload for 10m + expr: max_over_time(reloader_last_reload_successful{namespace=~".+"}[5m]) == 0 + for: {{ dig "ConfigReloaderSidecarErrors" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "ConfigReloaderSidecarErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.configReloaders }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.configReloaders }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/etcd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/etcd.yaml new file mode 100644 index 0000000000..a1d7a508f8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/etcd.yaml @@ -0,0 +1,461 @@ +{{- /* +Generated from 'etcd' group from https://github.com/etcd-io/etcd.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.etcd }} +{{- if (include "exporter.kubeEtcd.enabled" .)}} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "etcd" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: etcd + rules: +{{- if not (.Values.defaultRules.disabled.etcdMembersDown | default false) }} + - alert: etcdMembersDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": members are down ({{`{{`}} $value {{`}}`}}).' + summary: etcd cluster members are down. + expr: |- + max without (endpoint) ( + sum without (instance) (up{job=~".*etcd.*"} == bool 0) + or + count without (To) ( + sum without (instance) (rate(etcd_network_peer_sent_failures_total{job=~".*etcd.*"}[120s])) > 0.01 + ) + ) + > 0 + for: {{ dig "etcdMembersDown" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdMembersDown" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdInsufficientMembers | default false) }} + - alert: etcdInsufficientMembers + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": insufficient members ({{`{{`}} $value {{`}}`}}).' + summary: etcd cluster has insufficient number of members. + expr: sum(up{job=~".*etcd.*"} == bool 1) without (instance) < ((count(up{job=~".*etcd.*"}) without (instance) + 1) / 2) + for: {{ dig "etcdInsufficientMembers" "for" "3m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdInsufficientMembers" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdNoLeader | default false) }} + - alert: etcdNoLeader + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": member {{`{{`}} $labels.instance {{`}}`}} has no leader.' + summary: etcd cluster has no leader. + expr: etcd_server_has_leader{job=~".*etcd.*"} == 0 + for: {{ dig "etcdNoLeader" "for" "1m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdNoLeader" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdHighNumberOfLeaderChanges | default false) }} + - alert: etcdHighNumberOfLeaderChanges + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": {{`{{`}} $value {{`}}`}} leader changes within the last 15 minutes. Frequent elections may be a sign of insufficient resources, high network latency, or disruptions by other components and should be investigated.' + summary: etcd cluster has high number of leader changes. + expr: increase((max without (instance) (etcd_server_leader_changes_seen_total{job=~".*etcd.*"}) or 0*absent(etcd_server_leader_changes_seen_total{job=~".*etcd.*"}))[15m:1m]) >= 4 + for: {{ dig "etcdHighNumberOfLeaderChanges" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdHighNumberOfLeaderChanges" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdHighNumberOfFailedGRPCRequests | default false) }} + - alert: etcdHighNumberOfFailedGRPCRequests + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": {{`{{`}} $value {{`}}`}}% of requests for {{`{{`}} $labels.grpc_method {{`}}`}} failed on etcd instance {{`{{`}} $labels.instance {{`}}`}}.' + summary: etcd cluster has high number of failed grpc requests. + expr: |- + 100 * sum(rate(grpc_server_handled_total{job=~".*etcd.*", grpc_code=~"Unknown|FailedPrecondition|ResourceExhausted|Internal|Unavailable|DataLoss|DeadlineExceeded"}[5m])) without (grpc_type, grpc_code) + / + sum(rate(grpc_server_handled_total{job=~".*etcd.*"}[5m])) without (grpc_type, grpc_code) + > 1 + for: {{ dig "etcdHighNumberOfFailedGRPCRequests" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdHighNumberOfFailedGRPCRequests" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdHighNumberOfFailedGRPCRequests | default false) }} + - alert: etcdHighNumberOfFailedGRPCRequests + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": {{`{{`}} $value {{`}}`}}% of requests for {{`{{`}} $labels.grpc_method {{`}}`}} failed on etcd instance {{`{{`}} $labels.instance {{`}}`}}.' + summary: etcd cluster has high number of failed grpc requests. + expr: |- + 100 * sum(rate(grpc_server_handled_total{job=~".*etcd.*", grpc_code=~"Unknown|FailedPrecondition|ResourceExhausted|Internal|Unavailable|DataLoss|DeadlineExceeded"}[5m])) without (grpc_type, grpc_code) + / + sum(rate(grpc_server_handled_total{job=~".*etcd.*"}[5m])) without (grpc_type, grpc_code) + > 5 + for: {{ dig "etcdHighNumberOfFailedGRPCRequests" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdHighNumberOfFailedGRPCRequests" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdGRPCRequestsSlow | default false) }} + - alert: etcdGRPCRequestsSlow + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": 99th percentile of gRPC requests is {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}} for {{`{{`}} $labels.grpc_method {{`}}`}} method.' + summary: etcd grpc requests are slow + expr: |- + histogram_quantile(0.99, sum(rate(grpc_server_handling_seconds_bucket{job=~".*etcd.*", grpc_method!="Defragment", grpc_type="unary"}[5m])) without(grpc_type)) + > 0.15 + for: {{ dig "etcdGRPCRequestsSlow" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdGRPCRequestsSlow" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdMemberCommunicationSlow | default false) }} + - alert: etcdMemberCommunicationSlow + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": member communication with {{`{{`}} $labels.To {{`}}`}} is taking {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}}.' + summary: etcd cluster member communication is slow. + expr: |- + histogram_quantile(0.99, rate(etcd_network_peer_round_trip_time_seconds_bucket{job=~".*etcd.*"}[5m])) + > 0.15 + for: {{ dig "etcdMemberCommunicationSlow" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdMemberCommunicationSlow" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdHighNumberOfFailedProposals | default false) }} + - alert: etcdHighNumberOfFailedProposals + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": {{`{{`}} $value {{`}}`}} proposal failures within the last 30 minutes on etcd instance {{`{{`}} $labels.instance {{`}}`}}.' + summary: etcd cluster has high number of proposal failures. + expr: rate(etcd_server_proposals_failed_total{job=~".*etcd.*"}[15m]) > 5 + for: {{ dig "etcdHighNumberOfFailedProposals" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdHighNumberOfFailedProposals" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdHighFsyncDurations | default false) }} + - alert: etcdHighFsyncDurations + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": 99th percentile fsync durations are {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}}.' + summary: etcd cluster 99th percentile fsync durations are too high. + expr: |- + histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket{job=~".*etcd.*"}[5m])) + > 0.5 + for: {{ dig "etcdHighFsyncDurations" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdHighFsyncDurations" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdHighFsyncDurations | default false) }} + - alert: etcdHighFsyncDurations + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": 99th percentile fsync durations are {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}}.' + summary: etcd cluster 99th percentile fsync durations are too high. + expr: |- + histogram_quantile(0.99, rate(etcd_disk_wal_fsync_duration_seconds_bucket{job=~".*etcd.*"}[5m])) + > 1 + for: {{ dig "etcdHighFsyncDurations" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdHighFsyncDurations" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdHighCommitDurations | default false) }} + - alert: etcdHighCommitDurations + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": 99th percentile commit durations {{`{{`}} $value {{`}}`}}s on etcd instance {{`{{`}} $labels.instance {{`}}`}}.' + summary: etcd cluster 99th percentile commit durations are too high. + expr: |- + histogram_quantile(0.99, rate(etcd_disk_backend_commit_duration_seconds_bucket{job=~".*etcd.*"}[5m])) + > 0.25 + for: {{ dig "etcdHighCommitDurations" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdHighCommitDurations" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdDatabaseQuotaLowSpace | default false) }} + - alert: etcdDatabaseQuotaLowSpace + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": database size exceeds the defined quota on etcd instance {{`{{`}} $labels.instance {{`}}`}}, please defrag or increase the quota as the writes to etcd will be disabled when it is full.' + summary: etcd cluster database is running full. + expr: (last_over_time(etcd_mvcc_db_total_size_in_bytes{job=~".*etcd.*"}[5m]) / last_over_time(etcd_server_quota_backend_bytes{job=~".*etcd.*"}[5m]))*100 > 95 + for: {{ dig "etcdDatabaseQuotaLowSpace" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdDatabaseQuotaLowSpace" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdExcessiveDatabaseGrowth | default false) }} + - alert: etcdExcessiveDatabaseGrowth + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": Predicting running out of disk space in the next four hours, based on write observations within the past four hours on etcd instance {{`{{`}} $labels.instance {{`}}`}}, please check as it might be disruptive.' + summary: etcd cluster database growing very fast. + expr: predict_linear(etcd_mvcc_db_total_size_in_bytes{job=~".*etcd.*"}[4h], 4*60*60) > etcd_server_quota_backend_bytes{job=~".*etcd.*"} + for: {{ dig "etcdExcessiveDatabaseGrowth" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdExcessiveDatabaseGrowth" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.etcdDatabaseHighFragmentationRatio | default false) }} + - alert: etcdDatabaseHighFragmentationRatio + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.etcd }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.etcd | indent 8 }} +{{- end }} + description: 'etcd cluster "{{`{{`}} $labels.job {{`}}`}}": database size in use on instance {{`{{`}} $labels.instance {{`}}`}} is {{`{{`}} $value | humanizePercentage {{`}}`}} of the actual allocated disk space, please run defragmentation (e.g. etcdctl defrag) to retrieve the unused fragmented disk space.' + runbook_url: https://etcd.io/docs/v3.5/op-guide/maintenance/#defragmentation + summary: etcd database size in use is less than 50% of the actual allocated storage. + expr: (last_over_time(etcd_mvcc_db_total_size_in_use_in_bytes{job=~".*etcd.*"}[5m]) / last_over_time(etcd_mvcc_db_total_size_in_bytes{job=~".*etcd.*"}[5m])) < 0.5 and etcd_mvcc_db_total_size_in_use_in_bytes{job=~".*etcd.*"} > 104857600 + for: {{ dig "etcdDatabaseHighFragmentationRatio" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "etcdDatabaseHighFragmentationRatio" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.etcd }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/general.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/general.rules.yaml new file mode 100644 index 0000000000..6324228838 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/general.rules.yaml @@ -0,0 +1,125 @@ +{{- /* +Generated from 'general.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.general }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "general.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: general.rules + rules: +{{- if not (.Values.defaultRules.disabled.TargetDown | default false) }} + - alert: TargetDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.general }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.general | indent 8 }} +{{- end }} + description: '{{`{{`}} printf "%.4g" $value {{`}}`}}% of the {{`{{`}} $labels.job {{`}}`}}/{{`{{`}} $labels.service {{`}}`}} targets in {{`{{`}} $labels.namespace {{`}}`}} namespace are down.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/general/targetdown + summary: One or more targets are unreachable. + expr: 100 * (count(up == 0) BY (cluster, job, namespace, service) / count(up) BY (cluster, job, namespace, service)) > 10 + for: {{ dig "TargetDown" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "TargetDown" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.general }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.general }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.Watchdog | default false) }} + - alert: Watchdog + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.general }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.general | indent 8 }} +{{- end }} + description: 'This is an alert meant to ensure that the entire alerting pipeline is functional. + + This alert is always firing, therefore it should always be firing in Alertmanager + + and always fire against a receiver. There are integrations with various notification + + mechanisms that send a notification when this alert is not firing. For example the + + "DeadMansSnitch" integration in PagerDuty. + + ' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/general/watchdog + summary: An alert that should always be firing to certify that Alertmanager is working properly. + expr: vector(1) + labels: + severity: {{ dig "Watchdog" "severity" "none" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.general }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.general }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.InfoInhibitor | default false) }} + - alert: InfoInhibitor + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.general }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.general | indent 8 }} +{{- end }} + description: 'This is an alert that is used to inhibit info alerts. + + By themselves, the info-level alerts are sometimes very noisy, but they are relevant when combined with + + other alerts. + + This alert fires whenever there''s a severity="info" alert, and stops firing when another alert with a + + severity of ''warning'' or ''critical'' starts firing on the same namespace. + + This alert should be routed to a null receiver and configured to inhibit alerts with severity="info". + + ' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/general/infoinhibitor + summary: Info-level alert inhibition. + expr: ALERTS{severity = "info"} == 1 unless on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace) ALERTS{alertname != "InfoInhibitor", severity =~ "warning|critical", alertstate="firing"} == 1 + labels: + severity: {{ dig "InfoInhibitor" "severity" "none" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.general }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.general }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_cpu_usage_seconds_total.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_cpu_usage_seconds_total.yaml new file mode 100644 index 0000000000..19aa6b4e25 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_cpu_usage_seconds_total.yaml @@ -0,0 +1,43 @@ +{{- /* +Generated from 'k8s.rules.container-cpu-usage-seconds-total' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8sContainerCpuUsageSecondsTotal }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules.container-cpu-usage-seconds-total" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: k8s.rules.container_cpu_usage_seconds_total + rules: + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, container) ( + irate(container_cpu_usage_seconds_total{job="kubelet", metrics_path="/metrics/cadvisor", image!=""}[5m]) + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) group_left(node) topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) ( + 1, max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerCpuUsageSecondsTotal }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerCpuUsageSecondsTotal }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_cache.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_cache.yaml new file mode 100644 index 0000000000..2a08f43838 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_cache.yaml @@ -0,0 +1,42 @@ +{{- /* +Generated from 'k8s.rules.container-memory-cache' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8sContainerMemoryCache }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules.container-memory-cache" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: k8s.rules.container_memory_cache + rules: + - expr: |- + container_memory_cache{job="kubelet", metrics_path="/metrics/cadvisor", image!=""} + * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) group_left(node) topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) (1, + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_memory_cache + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerMemoryCache }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerMemoryCache }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_rss.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_rss.yaml new file mode 100644 index 0000000000..85b23faafa --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_rss.yaml @@ -0,0 +1,42 @@ +{{- /* +Generated from 'k8s.rules.container-memory-rss' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8sContainerMemoryRss }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules.container-memory-rss" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: k8s.rules.container_memory_rss + rules: + - expr: |- + container_memory_rss{job="kubelet", metrics_path="/metrics/cadvisor", image!=""} + * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) group_left(node) topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) (1, + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_memory_rss + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerMemoryRss }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerMemoryRss }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_swap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_swap.yaml new file mode 100644 index 0000000000..aae26802ed --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_swap.yaml @@ -0,0 +1,42 @@ +{{- /* +Generated from 'k8s.rules.container-memory-swap' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8sContainerMemorySwap }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules.container-memory-swap" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: k8s.rules.container_memory_swap + rules: + - expr: |- + container_memory_swap{job="kubelet", metrics_path="/metrics/cadvisor", image!=""} + * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) group_left(node) topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) (1, + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_memory_swap + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerMemorySwap }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerMemorySwap }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_working_set_bytes.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_working_set_bytes.yaml new file mode 100644 index 0000000000..cc7fbbd063 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_memory_working_set_bytes.yaml @@ -0,0 +1,42 @@ +{{- /* +Generated from 'k8s.rules.container-memory-working-set-bytes' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8sContainerMemoryWorkingSetBytes }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules.container-memory-working-set-bytes" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: k8s.rules.container_memory_working_set_bytes + rules: + - expr: |- + container_memory_working_set_bytes{job="kubelet", metrics_path="/metrics/cadvisor", image!=""} + * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) group_left(node) topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) (1, + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_memory_working_set_bytes + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerMemoryWorkingSetBytes }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerMemoryWorkingSetBytes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_resource.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_resource.yaml new file mode 100644 index 0000000000..edba0c2e01 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.container_resource.yaml @@ -0,0 +1,168 @@ +{{- /* +Generated from 'k8s.rules.container-resource' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8sContainerResource }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules.container-resource" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: k8s.rules.container_resource + rules: + - expr: |- + kube_pod_container_resource_requests{resource="memory",job="{{ $kubeStateMetricsJob }}"} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) + group_left() max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + (kube_pod_status_phase{phase=~"Pending|Running"} == 1) + ) + record: cluster:namespace:pod_memory:active:kube_pod_container_resource_requests + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, cluster) ( + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, container, cluster) ( + kube_pod_container_resource_requests{resource="memory",job="{{ $kubeStateMetricsJob }}"} + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) group_left() max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + ) + record: namespace_memory:kube_pod_container_resource_requests:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + kube_pod_container_resource_requests{resource="cpu",job="{{ $kubeStateMetricsJob }}"} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) + group_left() max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + (kube_pod_status_phase{phase=~"Pending|Running"} == 1) + ) + record: cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, cluster) ( + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, container, cluster) ( + kube_pod_container_resource_requests{resource="cpu",job="{{ $kubeStateMetricsJob }}"} + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) group_left() max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + ) + record: namespace_cpu:kube_pod_container_resource_requests:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + kube_pod_container_resource_limits{resource="memory",job="{{ $kubeStateMetricsJob }}"} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) + group_left() max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + (kube_pod_status_phase{phase=~"Pending|Running"} == 1) + ) + record: cluster:namespace:pod_memory:active:kube_pod_container_resource_limits + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, cluster) ( + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, container, cluster) ( + kube_pod_container_resource_limits{resource="memory",job="{{ $kubeStateMetricsJob }}"} + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) group_left() max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + ) + record: namespace_memory:kube_pod_container_resource_limits:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + kube_pod_container_resource_limits{resource="cpu",job="{{ $kubeStateMetricsJob }}"} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) + group_left() max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + (kube_pod_status_phase{phase=~"Pending|Running"} == 1) + ) + record: cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, cluster) ( + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, container, cluster) ( + kube_pod_container_resource_limits{resource="cpu",job="{{ $kubeStateMetricsJob }}"} + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) group_left() max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + ) + record: namespace_cpu:kube_pod_container_resource_limits:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sContainerResource }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.pod_owner.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.pod_owner.yaml new file mode 100644 index 0000000000..43207a748c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.pod_owner.yaml @@ -0,0 +1,107 @@ +{{- /* +Generated from 'k8s.rules.pod-owner' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8sPodOwner }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules.pod-owner" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: k8s.rules.pod_owner + rules: + - expr: |- + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, workload, pod) ( + label_replace( + label_replace( + kube_pod_owner{job="{{ $kubeStateMetricsJob }}", owner_kind="ReplicaSet"}, + "replicaset", "$1", "owner_name", "(.*)" + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}replicaset, namespace) group_left(owner_name) topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}replicaset, namespace) ( + 1, max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}replicaset, namespace, owner_name) ( + kube_replicaset_owner{job="{{ $kubeStateMetricsJob }}"} + ) + ), + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: deployment + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sPodOwner }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sPodOwner }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: |- + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job="{{ $kubeStateMetricsJob }}", owner_kind="DaemonSet"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: daemonset + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sPodOwner }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sPodOwner }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: |- + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job="{{ $kubeStateMetricsJob }}", owner_kind="StatefulSet"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: statefulset + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sPodOwner }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sPodOwner }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: |- + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job="{{ $kubeStateMetricsJob }}", owner_kind="Job"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: job + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.k8sPodOwner }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.k8sPodOwner }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: namespace_workload_pod:kube_pod_owner:relabel +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.yaml new file mode 100644 index 0000000000..c61bd222ab --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/k8s.rules.yaml @@ -0,0 +1,237 @@ +{{- /* +Generated from 'k8s.rules' group from https://raw.githubusercontent.com/prometheus-operator/kube-prometheus/main/manifests/kubernetesControlPlane-prometheusRule.yaml +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.k8s }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "k8s.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: k8s.rules + rules: + - expr: |- + sum by (cluster, namespace, pod, container) ( + irate(container_cpu_usage_seconds_total{job="{{ include "exporter.kubelet.jobName" . }}", metrics_path="/metrics/cadvisor", image!=""}[5m]) + ) * on (cluster, namespace, pod) group_left(node) topk by (cluster, namespace, pod) ( + 1, max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + container_memory_working_set_bytes{job="kubelet", metrics_path="/metrics/cadvisor", image!=""} + * on (cluster, namespace, pod) group_left(node) topk by(cluster, namespace, pod) (1, + max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_memory_working_set_bytes + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + container_memory_rss{job="kubelet", metrics_path="/metrics/cadvisor", image!=""} + * on (cluster, namespace, pod) group_left(node) topk by(cluster, namespace, pod) (1, + max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_memory_rss + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + container_memory_cache{job="kubelet", metrics_path="/metrics/cadvisor", image!=""} + * on (cluster, namespace, pod) group_left(node) topk by(cluster, namespace, pod) (1, + max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_memory_cache + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + container_memory_swap{job="kubelet", metrics_path="/metrics/cadvisor", image!=""} + * on (cluster, namespace, pod) group_left(node) topk by(cluster, namespace, pod) (1, + max by(cluster, namespace, pod, node) (kube_pod_info{node!=""}) + ) + record: node_namespace_pod_container:container_memory_swap + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"} * on (namespace, pod, cluster) + group_left() max by (namespace, pod, cluster) ( + (kube_pod_status_phase{phase=~"Pending|Running"} == 1) + ) + record: cluster:namespace:pod_memory:active:kube_pod_container_resource_requests + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + sum by (namespace, cluster) ( + sum by (namespace, pod, cluster) ( + max by (namespace, pod, container, cluster) ( + kube_pod_container_resource_requests{resource="memory",job="kube-state-metrics"} + ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + ) + record: namespace_memory:kube_pod_container_resource_requests:sum + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"} * on (namespace, pod, cluster) + group_left() max by (namespace, pod, cluster) ( + (kube_pod_status_phase{phase=~"Pending|Running"} == 1) + ) + record: cluster:namespace:pod_cpu:active:kube_pod_container_resource_requests + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + sum by (namespace, cluster) ( + sum by (namespace, pod, cluster) ( + max by (namespace, pod, container, cluster) ( + kube_pod_container_resource_requests{resource="cpu",job="kube-state-metrics"} + ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + ) + record: namespace_cpu:kube_pod_container_resource_requests:sum + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} * on (namespace, pod, cluster) + group_left() max by (namespace, pod, cluster) ( + (kube_pod_status_phase{phase=~"Pending|Running"} == 1) + ) + record: cluster:namespace:pod_memory:active:kube_pod_container_resource_limits + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + sum by (namespace, cluster) ( + sum by (namespace, pod, cluster) ( + max by (namespace, pod, container, cluster) ( + kube_pod_container_resource_limits{resource="memory",job="kube-state-metrics"} + ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + ) + record: namespace_memory:kube_pod_container_resource_limits:sum + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} * on (namespace, pod, cluster) + group_left() max by (namespace, pod, cluster) ( + (kube_pod_status_phase{phase=~"Pending|Running"} == 1) + ) + record: cluster:namespace:pod_cpu:active:kube_pod_container_resource_limits + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + sum by (namespace, cluster) ( + sum by (namespace, pod, cluster) ( + max by (namespace, pod, container, cluster) ( + kube_pod_container_resource_limits{resource="cpu",job="kube-state-metrics"} + ) * on(namespace, pod, cluster) group_left() max by (namespace, pod, cluster) ( + kube_pod_status_phase{phase=~"Pending|Running"} == 1 + ) + ) + ) + record: namespace_cpu:kube_pod_container_resource_limits:sum + {{- if .Values.defaultRules.additionalRuleLabels }} + labels: + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + - expr: |- + max by (cluster, namespace, workload, pod) ( + label_replace( + label_replace( + kube_pod_owner{job="kube-state-metrics", owner_kind="ReplicaSet"}, + "replicaset", "$1", "owner_name", "(.*)" + ) * on(replicaset, namespace) group_left(owner_name) topk by(replicaset, namespace) ( + 1, max by (replicaset, namespace, owner_name) ( + kube_replicaset_owner{job="kube-state-metrics"} + ) + ), + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: deployment + {{- if .Values.defaultRules.additionalRuleLabels }} + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: |- + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job="kube-state-metrics", owner_kind="DaemonSet"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: daemonset + {{- if .Values.defaultRules.additionalRuleLabels }} + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: |- + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job="kube-state-metrics", owner_kind="StatefulSet"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: statefulset + {{- if .Values.defaultRules.additionalRuleLabels }} + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + record: namespace_workload_pod:kube_pod_owner:relabel + - expr: |- + max by (cluster, namespace, workload, pod) ( + label_replace( + kube_pod_owner{job="kube-state-metrics", owner_kind="Job"}, + "workload", "$1", "owner_name", "(.*)" + ) + ) + labels: + workload_type: job + {{- if .Values.defaultRules.additionalRuleLabels }} + {{ toYaml .Values.defaultRules.additionalRuleLabels | nindent 8 }} + {{- end }} + record: namespace_workload_pod:kube_pod_owner:relabel +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-availability.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-availability.rules.yaml new file mode 100644 index 0000000000..02c8e7adbf --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-availability.rules.yaml @@ -0,0 +1,273 @@ +{{- /* +Generated from 'kube-apiserver-availability.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeApiServer.enabled .Values.defaultRules.rules.kubeApiserverAvailability }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-apiserver-availability.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - interval: 3m + name: kube-apiserver-availability.rules + rules: + - expr: avg_over_time(code_verb:apiserver_request_total:increase1h[30d]) * 24 * 30 + record: code_verb:apiserver_request_total:increase30d + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, code) (code_verb:apiserver_request_total:increase30d{verb=~"LIST|GET"}) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: code:apiserver_request_total:increase30d + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, code) (code_verb:apiserver_request_total:increase30d{verb=~"POST|PUT|PATCH|DELETE"}) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: code:apiserver_request_total:increase30d + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, verb, scope) (increase(apiserver_request_sli_duration_seconds_count{job="apiserver"}[1h])) + record: cluster_verb_scope:apiserver_request_sli_duration_seconds_count:increase1h + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, verb, scope) (avg_over_time(cluster_verb_scope:apiserver_request_sli_duration_seconds_count:increase1h[30d]) * 24 * 30) + record: cluster_verb_scope:apiserver_request_sli_duration_seconds_count:increase30d + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, verb, scope, le) (increase(apiserver_request_sli_duration_seconds_bucket[1h])) + record: cluster_verb_scope_le:apiserver_request_sli_duration_seconds_bucket:increase1h + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, verb, scope, le) (avg_over_time(cluster_verb_scope_le:apiserver_request_sli_duration_seconds_bucket:increase1h[30d]) * 24 * 30) + record: cluster_verb_scope_le:apiserver_request_sli_duration_seconds_bucket:increase30d + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + 1 - ( + ( + # write too slow + sum by (cluster) (cluster_verb_scope:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count:increase30d{verb=~"POST|PUT|PATCH|DELETE"}) + - + sum by (cluster) (cluster_verb_scope_le:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket:increase30d{verb=~"POST|PUT|PATCH|DELETE",le="1"}) + ) + + ( + # read too slow + sum by (cluster) (cluster_verb_scope:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count:increase30d{verb=~"LIST|GET"}) + - + ( + ( + sum by (cluster) (cluster_verb_scope_le:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope=~"resource|",le="1"}) + or + vector(0) + ) + + + sum by (cluster) (cluster_verb_scope_le:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope="namespace",le="5"}) + + + sum by (cluster) (cluster_verb_scope_le:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope="cluster",le="30"}) + ) + ) + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (code:apiserver_request_total:increase30d{code=~"5.."} or vector(0)) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (code:apiserver_request_total:increase30d) + labels: + verb: all + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:availability30d + - expr: |- + 1 - ( + sum by (cluster) (cluster_verb_scope:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count:increase30d{verb=~"LIST|GET"}) + - + ( + # too slow + ( + sum by (cluster) (cluster_verb_scope_le:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope=~"resource|",le="1"}) + or + vector(0) + ) + + + sum by (cluster) (cluster_verb_scope_le:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope="namespace",le="5"}) + + + sum by (cluster) (cluster_verb_scope_le:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket:increase30d{verb=~"LIST|GET",scope="cluster",le="30"}) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (code:apiserver_request_total:increase30d{verb="read",code=~"5.."} or vector(0)) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (code:apiserver_request_total:increase30d{verb="read"}) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:availability30d + - expr: |- + 1 - ( + ( + # too slow + sum by (cluster) (cluster_verb_scope:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count:increase30d{verb=~"POST|PUT|PATCH|DELETE"}) + - + sum by (cluster) (cluster_verb_scope_le:apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket:increase30d{verb=~"POST|PUT|PATCH|DELETE",le="1"}) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (code:apiserver_request_total:increase30d{verb="write",code=~"5.."} or vector(0)) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (code:apiserver_request_total:increase30d{verb="write"}) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:availability30d + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,code,resource) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[5m])) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: code_resource:apiserver_request_total:rate5m + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,code,resource) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[5m])) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: code_resource:apiserver_request_total:rate5m + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, code, verb) (increase(apiserver_request_total{job="apiserver",verb=~"LIST|GET|POST|PUT|PATCH|DELETE",code=~"2.."}[1h])) + record: code_verb:apiserver_request_total:increase1h + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, code, verb) (increase(apiserver_request_total{job="apiserver",verb=~"LIST|GET|POST|PUT|PATCH|DELETE",code=~"3.."}[1h])) + record: code_verb:apiserver_request_total:increase1h + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, code, verb) (increase(apiserver_request_total{job="apiserver",verb=~"LIST|GET|POST|PUT|PATCH|DELETE",code=~"4.."}[1h])) + record: code_verb:apiserver_request_total:increase1h + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, code, verb) (increase(apiserver_request_total{job="apiserver",verb=~"LIST|GET|POST|PUT|PATCH|DELETE",code=~"5.."}[1h])) + record: code_verb:apiserver_request_total:increase1h + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverAvailability }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-burnrate.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-burnrate.rules.yaml new file mode 100644 index 0000000000..49f4400a59 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-burnrate.rules.yaml @@ -0,0 +1,440 @@ +{{- /* +Generated from 'kube-apiserver-burnrate.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeApiServer.enabled .Values.defaultRules.rules.kubeApiserverBurnrate }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-apiserver-burnrate.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kube-apiserver-burnrate.rules + rules: + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[1d])) + - + ( + ( + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[1d])) + or + vector(0) + ) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[1d])) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[1d])) + ) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[1d])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[1d])) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate1d + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[1h])) + - + ( + ( + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[1h])) + or + vector(0) + ) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[1h])) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[1h])) + ) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[1h])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[1h])) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate1h + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[2h])) + - + ( + ( + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[2h])) + or + vector(0) + ) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[2h])) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[2h])) + ) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[2h])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[2h])) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate2h + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[30m])) + - + ( + ( + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[30m])) + or + vector(0) + ) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[30m])) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[30m])) + ) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[30m])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[30m])) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate30m + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[3d])) + - + ( + ( + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[3d])) + or + vector(0) + ) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[3d])) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[3d])) + ) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[3d])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[3d])) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate3d + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[5m])) + - + ( + ( + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[5m])) + or + vector(0) + ) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[5m])) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[5m])) + ) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[5m])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[5m])) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate5m + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[6h])) + - + ( + ( + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope=~"resource|",le="1"}[6h])) + or + vector(0) + ) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="namespace",le="5"}[6h])) + + + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward",scope="cluster",le="30"}[6h])) + ) + ) + + + # errors + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET",code=~"5.."}[6h])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"LIST|GET"}[6h])) + labels: + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate6h + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[1d])) + - + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[1d])) + ) + + + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[1d])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[1d])) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate1d + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[1h])) + - + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[1h])) + ) + + + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[1h])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[1h])) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate1h + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[2h])) + - + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[2h])) + ) + + + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[2h])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[2h])) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate2h + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[30m])) + - + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[30m])) + ) + + + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[30m])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[30m])) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate30m + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[3d])) + - + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[3d])) + ) + + + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[3d])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[3d])) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate3d + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[5m])) + - + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[5m])) + ) + + + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[5m])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[5m])) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate5m + - expr: |- + ( + ( + # too slow + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_count{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[6h])) + - + sum by (cluster) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward",le="1"}[6h])) + ) + + + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",code=~"5.."}[6h])) + ) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(apiserver_request_total{job="apiserver",verb=~"POST|PUT|PATCH|DELETE"}[6h])) + labels: + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverBurnrate }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: apiserver_request:burnrate6h +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-histogram.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-histogram.rules.yaml new file mode 100644 index 0000000000..5d08aa4349 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-histogram.rules.yaml @@ -0,0 +1,53 @@ +{{- /* +Generated from 'kube-apiserver-histogram.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeApiServer.enabled .Values.defaultRules.rules.kubeApiserverHistogram }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-apiserver-histogram.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kube-apiserver-histogram.rules + rules: + - expr: histogram_quantile(0.99, sum by (cluster, le, resource) (rate(apiserver_request{{ if (semverCompare ">=1.23.0-0" $kubeTargetVersion) }}_slo{{ end }}_duration_seconds_bucket{job="apiserver",verb=~"LIST|GET",subresource!~"proxy|attach|log|exec|portforward"}[5m]))) > 0 + labels: + quantile: '0.99' + verb: read + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverHistogram }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverHistogram }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:apiserver_request_sli_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.99, sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, le, resource) (rate(apiserver_request_sli_duration_seconds_bucket{job="apiserver",verb=~"POST|PUT|PATCH|DELETE",subresource!~"proxy|attach|log|exec|portforward"}[5m]))) > 0 + labels: + quantile: '0.99' + verb: write + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverHistogram }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverHistogram }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:apiserver_request_sli_duration_seconds:histogram_quantile +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-slos.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-slos.yaml new file mode 100644 index 0000000000..a83cf9060c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-apiserver-slos.yaml @@ -0,0 +1,159 @@ +{{- /* +Generated from 'kube-apiserver-slos' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeApiServer.enabled .Values.defaultRules.rules.kubeApiserverSlos }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-apiserver-slos" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kube-apiserver-slos + rules: +{{- if not (.Values.defaultRules.disabled.KubeAPIErrorBudgetBurn | default false) }} + - alert: KubeAPIErrorBudgetBurn + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeApiserverSlos }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeApiserverSlos | indent 8 }} +{{- end }} + description: The API server is burning too much error budget. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapierrorbudgetburn + summary: The API server is burning too much error budget. + expr: |- + sum(apiserver_request:burnrate1h) > (14.40 * 0.01000) + and + sum(apiserver_request:burnrate5m) > (14.40 * 0.01000) + for: {{ dig "KubeAPIErrorBudgetBurn" "for" "2m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + long: 1h + severity: {{ dig "KubeAPIErrorBudgetBurn" "severity" "critical" .Values.customRules }} + short: 5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverSlos }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverSlos }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeAPIErrorBudgetBurn | default false) }} + - alert: KubeAPIErrorBudgetBurn + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeApiserverSlos }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeApiserverSlos | indent 8 }} +{{- end }} + description: The API server is burning too much error budget. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapierrorbudgetburn + summary: The API server is burning too much error budget. + expr: |- + sum(apiserver_request:burnrate6h) > (6.00 * 0.01000) + and + sum(apiserver_request:burnrate30m) > (6.00 * 0.01000) + for: {{ dig "KubeAPIErrorBudgetBurn" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + long: 6h + severity: {{ dig "KubeAPIErrorBudgetBurn" "severity" "critical" .Values.customRules }} + short: 30m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverSlos }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverSlos }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeAPIErrorBudgetBurn | default false) }} + - alert: KubeAPIErrorBudgetBurn + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeApiserverSlos }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeApiserverSlos | indent 8 }} +{{- end }} + description: The API server is burning too much error budget. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapierrorbudgetburn + summary: The API server is burning too much error budget. + expr: |- + sum(apiserver_request:burnrate1d) > (3.00 * 0.01000) + and + sum(apiserver_request:burnrate2h) > (3.00 * 0.01000) + for: {{ dig "KubeAPIErrorBudgetBurn" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + long: 1d + severity: {{ dig "KubeAPIErrorBudgetBurn" "severity" "warning" .Values.customRules }} + short: 2h + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverSlos }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverSlos }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeAPIErrorBudgetBurn | default false) }} + - alert: KubeAPIErrorBudgetBurn + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeApiserverSlos }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeApiserverSlos | indent 8 }} +{{- end }} + description: The API server is burning too much error budget. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapierrorbudgetburn + summary: The API server is burning too much error budget. + expr: |- + sum(apiserver_request:burnrate3d) > (1.00 * 0.01000) + and + sum(apiserver_request:burnrate6h) > (1.00 * 0.01000) + for: {{ dig "KubeAPIErrorBudgetBurn" "for" "3h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + long: 3d + severity: {{ dig "KubeAPIErrorBudgetBurn" "severity" "warning" .Values.customRules }} + short: 6h + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverSlos }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeApiserverSlos }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-prometheus-general.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-prometheus-general.rules.yaml new file mode 100644 index 0000000000..fc199f11f8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-prometheus-general.rules.yaml @@ -0,0 +1,49 @@ +{{- /* +Generated from 'kube-prometheus-general.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubePrometheusGeneral }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-prometheus-general.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kube-prometheus-general.rules + rules: + - expr: count without(instance, pod, node) (up == 1) + record: count:up1 + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusGeneral }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusGeneral }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: count without(instance, pod, node) (up == 0) + record: count:up0 + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusGeneral }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusGeneral }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-prometheus-node-recording.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-prometheus-node-recording.rules.yaml new file mode 100644 index 0000000000..63f721f42a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-prometheus-node-recording.rules.yaml @@ -0,0 +1,93 @@ +{{- /* +Generated from 'kube-prometheus-node-recording.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubePrometheusNodeRecording }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-prometheus-node-recording.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kube-prometheus-node-recording.rules + rules: + - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[3m])) BY ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance) + record: instance:node_cpu:rate:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum(rate(node_network_receive_bytes_total[3m])) BY ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance) + record: instance:node_network_receive_bytes:rate:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum(rate(node_network_transmit_bytes_total[3m])) BY ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance) + record: instance:node_network_transmit_bytes:rate:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[5m])) WITHOUT (cpu, mode) / ON ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance) GROUP_LEFT() count(sum(node_cpu_seconds_total) BY ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance, cpu)) BY ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance) + record: instance:node_cpu:ratio + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum(rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal"}[5m])) + record: cluster:node_cpu:sum_rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: cluster:node_cpu:sum_rate5m / count(sum(node_cpu_seconds_total) BY ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance, cpu)) + record: cluster:node_cpu:ratio + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubePrometheusNodeRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-scheduler.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-scheduler.rules.yaml new file mode 100644 index 0000000000..9f8bf60228 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-scheduler.rules.yaml @@ -0,0 +1,135 @@ +{{- /* +Generated from 'kube-scheduler.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeScheduler.enabled .Values.defaultRules.rules.kubeSchedulerRecording }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-scheduler.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kube-scheduler.rules + rules: + - expr: histogram_quantile(0.99, sum(rate(scheduler_e2e_scheduling_duration_seconds_bucket{job="{{ include "exporter.kubeScheduler.jobName" . }}"}[5m])) without(instance, pod)) + labels: + quantile: '0.99' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_e2e_scheduling_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.99, sum(rate(scheduler_scheduling_algorithm_duration_seconds_bucket{job="{{ include "exporter.kubeScheduler.jobName" . }}"}[5m])) without(instance, pod)) + labels: + quantile: '0.99' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_scheduling_algorithm_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.99, sum(rate(scheduler_binding_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod)) + labels: + quantile: '0.99' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_binding_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.9, sum(rate(scheduler_e2e_scheduling_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod)) + labels: + quantile: '0.9' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_e2e_scheduling_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.9, sum(rate(scheduler_scheduling_algorithm_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod)) + labels: + quantile: '0.9' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_scheduling_algorithm_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.9, sum(rate(scheduler_binding_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod)) + labels: + quantile: '0.9' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_binding_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.5, sum(rate(scheduler_e2e_scheduling_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod)) + labels: + quantile: '0.5' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_e2e_scheduling_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.5, sum(rate(scheduler_scheduling_algorithm_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod)) + labels: + quantile: '0.5' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_scheduling_algorithm_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.5, sum(rate(scheduler_binding_duration_seconds_bucket{job="kube-scheduler"}[5m])) without(instance, pod)) + labels: + quantile: '0.5' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: cluster_quantile:scheduler_binding_duration_seconds:histogram_quantile +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-state-metrics.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-state-metrics.yaml new file mode 100644 index 0000000000..7f3600fb71 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kube-state-metrics.yaml @@ -0,0 +1,152 @@ +{{- /* +Generated from 'kube-state-metrics' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubeStateMetrics }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kube-state-metrics" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kube-state-metrics + rules: +{{- if not (.Values.defaultRules.disabled.KubeStateMetricsListErrors | default false) }} + - alert: KubeStateMetricsListErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeStateMetrics }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeStateMetrics | indent 8 }} +{{- end }} + description: kube-state-metrics is experiencing errors at an elevated rate in list operations. This is likely causing it to not be able to expose metrics about Kubernetes objects correctly or at all. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kube-state-metrics/kubestatemetricslisterrors + summary: kube-state-metrics is experiencing errors in list operations. + expr: |- + (sum(rate(kube_state_metrics_list_total{job="{{ $kubeStateMetricsJob }}",result="error"}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) + / + sum(rate(kube_state_metrics_list_total{job="{{ $kubeStateMetricsJob }}"}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster)) + > 0.01 + for: {{ dig "KubeStateMetricsListErrors" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeStateMetricsListErrors" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeStateMetrics }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeStateMetrics }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeStateMetricsWatchErrors | default false) }} + - alert: KubeStateMetricsWatchErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeStateMetrics }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeStateMetrics | indent 8 }} +{{- end }} + description: kube-state-metrics is experiencing errors at an elevated rate in watch operations. This is likely causing it to not be able to expose metrics about Kubernetes objects correctly or at all. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kube-state-metrics/kubestatemetricswatcherrors + summary: kube-state-metrics is experiencing errors in watch operations. + expr: |- + (sum(rate(kube_state_metrics_watch_total{job="{{ $kubeStateMetricsJob }}",result="error"}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) + / + sum(rate(kube_state_metrics_watch_total{job="{{ $kubeStateMetricsJob }}"}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster)) + > 0.01 + for: {{ dig "KubeStateMetricsWatchErrors" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeStateMetricsWatchErrors" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeStateMetrics }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeStateMetrics }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeStateMetricsShardingMismatch | default false) }} + - alert: KubeStateMetricsShardingMismatch + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeStateMetrics }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeStateMetrics | indent 8 }} +{{- end }} + description: kube-state-metrics pods are running with different --total-shards configuration, some Kubernetes objects may be exposed multiple times or not exposed at all. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kube-state-metrics/kubestatemetricsshardingmismatch + summary: kube-state-metrics sharding is misconfigured. + expr: stdvar (kube_state_metrics_total_shards{job="{{ $kubeStateMetricsJob }}"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) != 0 + for: {{ dig "KubeStateMetricsShardingMismatch" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeStateMetricsShardingMismatch" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeStateMetrics }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeStateMetrics }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeStateMetricsShardsMissing | default false) }} + - alert: KubeStateMetricsShardsMissing + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeStateMetrics }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeStateMetrics | indent 8 }} +{{- end }} + description: kube-state-metrics shards are missing, some Kubernetes objects are not being exposed. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kube-state-metrics/kubestatemetricsshardsmissing + summary: kube-state-metrics shards are missing. + expr: |- + 2^max(kube_state_metrics_total_shards{job="{{ $kubeStateMetricsJob }}"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) - 1 + - + sum( 2 ^ max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, shard_ordinal) (kube_state_metrics_shard_ordinal{job="{{ $kubeStateMetricsJob }}"}) ) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) + != 0 + for: {{ dig "KubeStateMetricsShardsMissing" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeStateMetricsShardsMissing" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeStateMetrics }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeStateMetrics }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubelet.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubelet.rules.yaml new file mode 100644 index 0000000000..8cd03baa43 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubelet.rules.yaml @@ -0,0 +1,65 @@ +{{- /* +Generated from 'kubelet.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubelet }} +{{- if (include "exporter.kubelet.enabled" .)}} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubelet.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubelet.rules + rules: + - expr: histogram_quantile(0.99, sum(rate(kubelet_pleg_relist_duration_seconds_bucket{job="kubelet", metrics_path="/metrics"}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance, le) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) group_left(node) kubelet_node_name{job="kubelet", metrics_path="/metrics"}) + labels: + quantile: '0.99' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubelet }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubelet }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: node_quantile:kubelet_pleg_relist_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.9, sum(rate(kubelet_pleg_relist_duration_seconds_bucket{job="kubelet", metrics_path="/metrics"}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance, le) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) group_left(node) kubelet_node_name{job="kubelet", metrics_path="/metrics"}) + labels: + quantile: '0.9' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubelet }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubelet }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: node_quantile:kubelet_pleg_relist_duration_seconds:histogram_quantile + - expr: histogram_quantile(0.5, sum(rate(kubelet_pleg_relist_duration_seconds_bucket{job="kubelet", metrics_path="/metrics"}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance, le) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) group_left(node) kubelet_node_name{job="kubelet", metrics_path="/metrics"}) + labels: + quantile: '0.5' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubelet }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubelet }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + record: node_quantile:kubelet_pleg_relist_duration_seconds:histogram_quantile +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-apps.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-apps.yaml new file mode 100644 index 0000000000..76215b3999 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-apps.yaml @@ -0,0 +1,568 @@ +{{- /* +Generated from 'kubernetes-apps' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesApps }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +{{- $targetNamespace := .Values.defaultRules.appNamespacesTarget }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-apps" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-apps + rules: +{{- if not (.Values.defaultRules.disabled.KubePodCrashLooping | default false) }} + - alert: KubePodCrashLooping + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: 'Pod {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod {{`}}`}} ({{`{{`}} $labels.container {{`}}`}}) is in waiting state (reason: "CrashLoopBackOff").' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepodcrashlooping + summary: Pod is crash looping. + expr: max_over_time(kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff", job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}[5m]) >= 1 + for: {{ dig "KubePodCrashLooping" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubePodCrashLooping" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubePodNotReady | default false) }} + - alert: KubePodNotReady + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: Pod {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod {{`}}`}} has been in a non-ready state for longer than 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepodnotready + summary: Pod has been in a non-ready state for more than 15 minutes. + expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + kube_pod_status_phase{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}", phase=~"Pending|Unknown|Failed"} + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) group_left(owner_kind) topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, cluster) ( + 1, max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, owner_kind, cluster) (kube_pod_owner{owner_kind!="Job"}) + ) + ) > 0 + for: {{ dig "KubePodNotReady" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubePodNotReady" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeDeploymentGenerationMismatch | default false) }} + - alert: KubeDeploymentGenerationMismatch + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: Deployment generation for {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.deployment {{`}}`}} does not match, this indicates that the Deployment has failed but has not been rolled back. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedeploymentgenerationmismatch + summary: Deployment generation mismatch due to possible roll-back + expr: |- + kube_deployment_status_observed_generation{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + kube_deployment_metadata_generation{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + for: {{ dig "KubeDeploymentGenerationMismatch" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeDeploymentGenerationMismatch" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeDeploymentReplicasMismatch | default false) }} + - alert: KubeDeploymentReplicasMismatch + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: Deployment {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.deployment {{`}}`}} has not matched the expected number of replicas for longer than 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedeploymentreplicasmismatch + summary: Deployment has not matched the expected number of replicas. + expr: |- + ( + kube_deployment_spec_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + > + kube_deployment_status_replicas_available{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + ) and ( + changes(kube_deployment_status_replicas_updated{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}[10m]) + == + 0 + ) + for: {{ dig "KubeDeploymentReplicasMismatch" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeDeploymentReplicasMismatch" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeDeploymentRolloutStuck | default false) }} + - alert: KubeDeploymentRolloutStuck + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: Rollout of deployment {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.deployment {{`}}`}} is not progressing for longer than 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedeploymentrolloutstuck + summary: Deployment rollout is not progressing. + expr: |- + kube_deployment_status_condition{condition="Progressing", status="false",job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != 0 + for: {{ dig "KubeDeploymentRolloutStuck" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeDeploymentRolloutStuck" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeStatefulSetReplicasMismatch | default false) }} + - alert: KubeStatefulSetReplicasMismatch + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: StatefulSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.statefulset {{`}}`}} has not matched the expected number of replicas for longer than 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubestatefulsetreplicasmismatch + summary: StatefulSet has not matched the expected number of replicas. + expr: |- + ( + kube_statefulset_status_replicas_ready{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + kube_statefulset_status_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + ) and ( + changes(kube_statefulset_status_replicas_updated{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}[10m]) + == + 0 + ) + for: {{ dig "KubeStatefulSetReplicasMismatch" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeStatefulSetReplicasMismatch" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeStatefulSetGenerationMismatch | default false) }} + - alert: KubeStatefulSetGenerationMismatch + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: StatefulSet generation for {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.statefulset {{`}}`}} does not match, this indicates that the StatefulSet has failed but has not been rolled back. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubestatefulsetgenerationmismatch + summary: StatefulSet generation mismatch due to possible roll-back + expr: |- + kube_statefulset_status_observed_generation{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + kube_statefulset_metadata_generation{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + for: {{ dig "KubeStatefulSetGenerationMismatch" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeStatefulSetGenerationMismatch" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeStatefulSetUpdateNotRolledOut | default false) }} + - alert: KubeStatefulSetUpdateNotRolledOut + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: StatefulSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.statefulset {{`}}`}} update has not been rolled out. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubestatefulsetupdatenotrolledout + summary: StatefulSet update has not been rolled out. + expr: |- + ( + max without (revision) ( + kube_statefulset_status_current_revision{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + unless + kube_statefulset_status_update_revision{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + ) + * + ( + kube_statefulset_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + kube_statefulset_status_replicas_updated{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + ) + ) and ( + changes(kube_statefulset_status_replicas_updated{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}[5m]) + == + 0 + ) + for: {{ dig "KubeStatefulSetUpdateNotRolledOut" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeStatefulSetUpdateNotRolledOut" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeDaemonSetRolloutStuck | default false) }} + - alert: KubeDaemonSetRolloutStuck + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: DaemonSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.daemonset {{`}}`}} has not finished or progressed for at least 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedaemonsetrolloutstuck + summary: DaemonSet rollout is stuck. + expr: |- + ( + ( + kube_daemonset_status_current_number_scheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + kube_daemonset_status_desired_number_scheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + ) or ( + kube_daemonset_status_number_misscheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + 0 + ) or ( + kube_daemonset_status_updated_number_scheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + kube_daemonset_status_desired_number_scheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + ) or ( + kube_daemonset_status_number_available{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + kube_daemonset_status_desired_number_scheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + ) + ) and ( + changes(kube_daemonset_status_updated_number_scheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}[5m]) + == + 0 + ) + for: {{ dig "KubeDaemonSetRolloutStuck" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeDaemonSetRolloutStuck" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeContainerWaiting | default false) }} + - alert: KubeContainerWaiting + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: pod/{{`{{`}} $labels.pod {{`}}`}} in namespace {{`{{`}} $labels.namespace {{`}}`}} on container {{`{{`}} $labels.container{{`}}`}} has been in waiting state for longer than 1 hour. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubecontainerwaiting + summary: Pod container waiting longer than 1 hour + expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, pod, container, cluster) (kube_pod_container_status_waiting_reason{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}) > 0 + for: {{ dig "KubeContainerWaiting" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeContainerWaiting" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeDaemonSetNotScheduled | default false) }} + - alert: KubeDaemonSetNotScheduled + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: '{{`{{`}} $value {{`}}`}} Pods of DaemonSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.daemonset {{`}}`}} are not scheduled.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedaemonsetnotscheduled + summary: DaemonSet pods are not scheduled. + expr: |- + kube_daemonset_status_desired_number_scheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + - + kube_daemonset_status_current_number_scheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} > 0 + for: {{ dig "KubeDaemonSetNotScheduled" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeDaemonSetNotScheduled" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeDaemonSetMisScheduled | default false) }} + - alert: KubeDaemonSetMisScheduled + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: '{{`{{`}} $value {{`}}`}} Pods of DaemonSet {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.daemonset {{`}}`}} are running where they are not supposed to run.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubedaemonsetmisscheduled + summary: DaemonSet pods are misscheduled. + expr: kube_daemonset_status_number_misscheduled{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} > 0 + for: {{ dig "KubeDaemonSetMisScheduled" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeDaemonSetMisScheduled" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeJobNotCompleted | default false) }} + - alert: KubeJobNotCompleted + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: Job {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.job_name {{`}}`}} is taking more than {{`{{`}} "43200" | humanizeDuration {{`}}`}} to complete. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubejobnotcompleted + summary: Job did not complete in time + expr: |- + time() - max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}namespace, job_name, cluster) (kube_job_status_start_time{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + and + kube_job_status_active{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} > 0) > 43200 + labels: + severity: {{ dig "KubeJobNotCompleted" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeJobFailed | default false) }} + - alert: KubeJobFailed + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: Job {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.job_name {{`}}`}} failed to complete. Removing failed job after investigation should clear this alert. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubejobfailed + summary: Job failed to complete. + expr: kube_job_failed{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} > 0 + for: {{ dig "KubeJobFailed" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeJobFailed" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeHpaReplicasMismatch | default false) }} + - alert: KubeHpaReplicasMismatch + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: HPA {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.horizontalpodautoscaler {{`}}`}} has not matched the desired number of replicas for longer than 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubehpareplicasmismatch + summary: HPA has not matched desired number of replicas. + expr: |- + (kube_horizontalpodautoscaler_status_desired_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + != + kube_horizontalpodautoscaler_status_current_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}) + and + (kube_horizontalpodautoscaler_status_current_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + > + kube_horizontalpodautoscaler_spec_min_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}) + and + (kube_horizontalpodautoscaler_status_current_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + < + kube_horizontalpodautoscaler_spec_max_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}) + and + changes(kube_horizontalpodautoscaler_status_current_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"}[15m]) == 0 + for: {{ dig "KubeHpaReplicasMismatch" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeHpaReplicasMismatch" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeHpaMaxedOut | default false) }} + - alert: KubeHpaMaxedOut + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesApps | indent 8 }} +{{- end }} + description: HPA {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.horizontalpodautoscaler {{`}}`}} has been running at max replicas for longer than 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubehpamaxedout + summary: HPA is running at max replicas + expr: |- + kube_horizontalpodautoscaler_status_current_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + == + kube_horizontalpodautoscaler_spec_max_replicas{job="{{ $kubeStateMetricsJob }}", namespace=~"{{ $targetNamespace }}"} + for: {{ dig "KubeHpaMaxedOut" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeHpaMaxedOut" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesApps }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-resources.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-resources.yaml new file mode 100644 index 0000000000..9111285250 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-resources.yaml @@ -0,0 +1,282 @@ +{{- /* +Generated from 'kubernetes-resources' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesResources }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-resources" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-resources + rules: +{{- if not (.Values.defaultRules.disabled.KubeCPUOvercommit | default false) }} + - alert: KubeCPUOvercommit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources | indent 8 }} +{{- end }} + description: Cluster {{`{{`}} $labels.cluster {{`}}`}} has overcommitted CPU resource requests for Pods by {{`{{`}} $value {{`}}`}} CPU shares and cannot tolerate node failure. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubecpuovercommit + summary: Cluster has overcommitted CPU resource requests. + expr: |- + sum(namespace_cpu:kube_pod_container_resource_requests:sum{job="{{ $kubeStateMetricsJob }}",}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) - (sum(kube_node_status_allocatable{job="{{ $kubeStateMetricsJob }}",resource="cpu"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) - max(kube_node_status_allocatable{job="{{ $kubeStateMetricsJob }}",resource="cpu"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster)) > 0 + and + (sum(kube_node_status_allocatable{job="{{ $kubeStateMetricsJob }}",resource="cpu"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) - max(kube_node_status_allocatable{job="{{ $kubeStateMetricsJob }}",resource="cpu"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster)) > 0 + for: {{ dig "KubeCPUOvercommit" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeCPUOvercommit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeMemoryOvercommit | default false) }} + - alert: KubeMemoryOvercommit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources | indent 8 }} +{{- end }} + description: Cluster {{`{{`}} $labels.cluster {{`}}`}} has overcommitted memory resource requests for Pods by {{`{{`}} $value | humanize {{`}}`}} bytes and cannot tolerate node failure. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubememoryovercommit + summary: Cluster has overcommitted memory resource requests. + expr: |- + sum(namespace_memory:kube_pod_container_resource_requests:sum{}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) - (sum(kube_node_status_allocatable{resource="memory", job="{{ $kubeStateMetricsJob }}"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) - max(kube_node_status_allocatable{resource="memory", job="{{ $kubeStateMetricsJob }}"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster)) > 0 + and + (sum(kube_node_status_allocatable{resource="memory", job="{{ $kubeStateMetricsJob }}"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) - max(kube_node_status_allocatable{resource="memory", job="{{ $kubeStateMetricsJob }}"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster)) > 0 + for: {{ dig "KubeMemoryOvercommit" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeMemoryOvercommit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeCPUQuotaOvercommit | default false) }} + - alert: KubeCPUQuotaOvercommit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources | indent 8 }} +{{- end }} + description: Cluster {{`{{`}} $labels.cluster {{`}}`}} has overcommitted CPU resource requests for Namespaces. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubecpuquotaovercommit + summary: Cluster has overcommitted CPU resource requests. + expr: |- + sum(min without(resource) (kube_resourcequota{job="{{ $kubeStateMetricsJob }}", type="hard", resource=~"(cpu|requests.cpu)"})) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) + / + sum(kube_node_status_allocatable{resource="cpu", job="{{ $kubeStateMetricsJob }}"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) + > 1.5 + for: {{ dig "KubeCPUQuotaOvercommit" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeCPUQuotaOvercommit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeMemoryQuotaOvercommit | default false) }} + - alert: KubeMemoryQuotaOvercommit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources | indent 8 }} +{{- end }} + description: Cluster {{`{{`}} $labels.cluster {{`}}`}} has overcommitted memory resource requests for Namespaces. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubememoryquotaovercommit + summary: Cluster has overcommitted memory resource requests. + expr: |- + sum(min without(resource) (kube_resourcequota{job="{{ $kubeStateMetricsJob }}", type="hard", resource=~"(memory|requests.memory)"})) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) + / + sum(kube_node_status_allocatable{resource="memory", job="{{ $kubeStateMetricsJob }}"}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) + > 1.5 + for: {{ dig "KubeMemoryQuotaOvercommit" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeMemoryQuotaOvercommit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeQuotaAlmostFull | default false) }} + - alert: KubeQuotaAlmostFull + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources | indent 8 }} +{{- end }} + description: Namespace {{`{{`}} $labels.namespace {{`}}`}} is using {{`{{`}} $value | humanizePercentage {{`}}`}} of its {{`{{`}} $labels.resource {{`}}`}} quota. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubequotaalmostfull + summary: Namespace quota is going to be full. + expr: |- + kube_resourcequota{job="{{ $kubeStateMetricsJob }}", type="used"} + / ignoring(instance, job, type) + (kube_resourcequota{job="{{ $kubeStateMetricsJob }}", type="hard"} > 0) + > 0.9 < 1 + for: {{ dig "KubeQuotaAlmostFull" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeQuotaAlmostFull" "severity" "info" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeQuotaFullyUsed | default false) }} + - alert: KubeQuotaFullyUsed + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources | indent 8 }} +{{- end }} + description: Namespace {{`{{`}} $labels.namespace {{`}}`}} is using {{`{{`}} $value | humanizePercentage {{`}}`}} of its {{`{{`}} $labels.resource {{`}}`}} quota. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubequotafullyused + summary: Namespace quota is fully used. + expr: |- + kube_resourcequota{job="{{ $kubeStateMetricsJob }}", type="used"} + / ignoring(instance, job, type) + (kube_resourcequota{job="{{ $kubeStateMetricsJob }}", type="hard"} > 0) + == 1 + for: {{ dig "KubeQuotaFullyUsed" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeQuotaFullyUsed" "severity" "info" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeQuotaExceeded | default false) }} + - alert: KubeQuotaExceeded + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources | indent 8 }} +{{- end }} + description: Namespace {{`{{`}} $labels.namespace {{`}}`}} is using {{`{{`}} $value | humanizePercentage {{`}}`}} of its {{`{{`}} $labels.resource {{`}}`}} quota. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubequotaexceeded + summary: Namespace quota has exceeded the limits. + expr: |- + kube_resourcequota{job="{{ $kubeStateMetricsJob }}", type="used"} + / ignoring(instance, job, type) + (kube_resourcequota{job="{{ $kubeStateMetricsJob }}", type="hard"} > 0) + > 1 + for: {{ dig "KubeQuotaExceeded" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeQuotaExceeded" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.CPUThrottlingHigh | default false) }} + - alert: CPUThrottlingHigh + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesResources | indent 8 }} +{{- end }} + description: '{{`{{`}} $value | humanizePercentage {{`}}`}} throttling of CPU in namespace {{`{{`}} $labels.namespace {{`}}`}} for container {{`{{`}} $labels.container {{`}}`}} in pod {{`{{`}} $labels.pod {{`}}`}}.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/cputhrottlinghigh + summary: Processes experience elevated CPU throttling. + expr: |- + sum(increase(container_cpu_cfs_throttled_periods_total{container!="", }[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, container, pod, namespace) + / + sum(increase(container_cpu_cfs_periods_total{}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, container, pod, namespace) + > ( 25 / 100 ) + for: {{ dig "CPUThrottlingHigh" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "CPUThrottlingHigh" "severity" "info" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesResources }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-storage.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-storage.yaml new file mode 100644 index 0000000000..809e544885 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-storage.yaml @@ -0,0 +1,216 @@ +{{- /* +Generated from 'kubernetes-storage' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesStorage }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +{{- $targetNamespace := .Values.defaultRules.appNamespacesTarget }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-storage" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-storage + rules: +{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeFillingUp | default false) }} + - alert: KubePersistentVolumeFillingUp + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage | indent 8 }} +{{- end }} + description: The PersistentVolume claimed by {{`{{`}} $labels.persistentvolumeclaim {{`}}`}} in Namespace {{`{{`}} $labels.namespace {{`}}`}} {{`{{`}} with $labels.cluster -{{`}}`}} on Cluster {{`{{`}} . {{`}}`}} {{`{{`}}- end {{`}}`}} is only {{`{{`}} $value | humanizePercentage {{`}}`}} free. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumefillingup + summary: PersistentVolume is filling up. + expr: |- + kubelet_volume_stats_available_bytes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} + / + kubelet_volume_stats_capacity_bytes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} + < 0.03 + and + kubelet_volume_stats_used_bytes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} > 0 + unless on(namespace, persistentvolumeclaim) + kube_persistentvolumeclaim_access_mode{ access_mode="ReadOnlyMany"} == 1 + unless on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, persistentvolumeclaim) + kube_persistentvolumeclaim_labels{label_excluded_from_alerts="true"} == 1 + for: {{ dig "KubePersistentVolumeFillingUp" "for" "1m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubePersistentVolumeFillingUp" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeFillingUp | default false) }} + - alert: KubePersistentVolumeFillingUp + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage | indent 8 }} +{{- end }} + description: Based on recent sampling, the PersistentVolume claimed by {{`{{`}} $labels.persistentvolumeclaim {{`}}`}} in Namespace {{`{{`}} $labels.namespace {{`}}`}} {{`{{`}} with $labels.cluster -{{`}}`}} on Cluster {{`{{`}} . {{`}}`}} {{`{{`}}- end {{`}}`}} is expected to fill up within four days. Currently {{`{{`}} $value | humanizePercentage {{`}}`}} is available. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumefillingup + summary: PersistentVolume is filling up. + expr: |- + ( + kubelet_volume_stats_available_bytes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} + / + kubelet_volume_stats_capacity_bytes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} + ) < 0.15 + and + kubelet_volume_stats_used_bytes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} > 0 + and + predict_linear(kubelet_volume_stats_available_bytes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}[6h], 4 * 24 * 3600) < 0 + unless on(namespace, persistentvolumeclaim) + kube_persistentvolumeclaim_access_mode{ access_mode="ReadOnlyMany"} == 1 + unless on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, persistentvolumeclaim) + kube_persistentvolumeclaim_labels{label_excluded_from_alerts="true"} == 1 + for: {{ dig "KubePersistentVolumeFillingUp" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubePersistentVolumeFillingUp" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeInodesFillingUp | default false) }} + - alert: KubePersistentVolumeInodesFillingUp + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage | indent 8 }} +{{- end }} + description: The PersistentVolume claimed by {{`{{`}} $labels.persistentvolumeclaim {{`}}`}} in Namespace {{`{{`}} $labels.namespace {{`}}`}} {{`{{`}} with $labels.cluster -{{`}}`}} on Cluster {{`{{`}} . {{`}}`}} {{`{{`}}- end {{`}}`}} only has {{`{{`}} $value | humanizePercentage {{`}}`}} free inodes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumeinodesfillingup + summary: PersistentVolumeInodes are filling up. + expr: |- + ( + kubelet_volume_stats_inodes_free{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} + / + kubelet_volume_stats_inodes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} + ) < 0.03 + and + kubelet_volume_stats_inodes_used{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} > 0 + unless on(namespace, persistentvolumeclaim) + kube_persistentvolumeclaim_access_mode{ access_mode="ReadOnlyMany"} == 1 + unless on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, persistentvolumeclaim) + kube_persistentvolumeclaim_labels{label_excluded_from_alerts="true"} == 1 + for: {{ dig "KubePersistentVolumeInodesFillingUp" "for" "1m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubePersistentVolumeInodesFillingUp" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeInodesFillingUp | default false) }} + - alert: KubePersistentVolumeInodesFillingUp + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage | indent 8 }} +{{- end }} + description: Based on recent sampling, the PersistentVolume claimed by {{`{{`}} $labels.persistentvolumeclaim {{`}}`}} in Namespace {{`{{`}} $labels.namespace {{`}}`}} {{`{{`}} with $labels.cluster -{{`}}`}} on Cluster {{`{{`}} . {{`}}`}} {{`{{`}}- end {{`}}`}} is expected to run out of inodes within four days. Currently {{`{{`}} $value | humanizePercentage {{`}}`}} of its inodes are free. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumeinodesfillingup + summary: PersistentVolumeInodes are filling up. + expr: |- + ( + kubelet_volume_stats_inodes_free{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} + / + kubelet_volume_stats_inodes{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} + ) < 0.15 + and + kubelet_volume_stats_inodes_used{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"} > 0 + and + predict_linear(kubelet_volume_stats_inodes_free{job="{{ include "exporter.kubelet.jobName" . }}", namespace=~"{{ $targetNamespace }}", metrics_path="/metrics"}[6h], 4 * 24 * 3600) < 0 + unless on(namespace, persistentvolumeclaim) + kube_persistentvolumeclaim_access_mode{ access_mode="ReadOnlyMany"} == 1 + unless on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, persistentvolumeclaim) + kube_persistentvolumeclaim_labels{label_excluded_from_alerts="true"} == 1 + for: {{ dig "KubePersistentVolumeInodesFillingUp" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubePersistentVolumeInodesFillingUp" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubePersistentVolumeErrors | default false) }} + - alert: KubePersistentVolumeErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesStorage | indent 8 }} +{{- end }} + description: The persistent volume {{`{{`}} $labels.persistentvolume {{`}}`}} {{`{{`}} with $labels.cluster -{{`}}`}} on Cluster {{`{{`}} . {{`}}`}} {{`{{`}}- end {{`}}`}} has status {{`{{`}} $labels.phase {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubepersistentvolumeerrors + summary: PersistentVolume is having issues with provisioning. + expr: kube_persistentvolume_status_phase{phase=~"Failed|Pending",job="{{ $kubeStateMetricsJob }}"} > 0 + for: {{ dig "KubePersistentVolumeErrors" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubePersistentVolumeErrors" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesStorage }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-apiserver.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-apiserver.yaml new file mode 100644 index 0000000000..6dd61b5f5c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-apiserver.yaml @@ -0,0 +1,193 @@ +{{- /* +Generated from 'kubernetes-system-apiserver' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesSystem }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-apiserver" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-system-apiserver + rules: +{{- if not (.Values.defaultRules.disabled.KubeClientCertificateExpiration | default false) }} + - alert: KubeClientCertificateExpiration + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: A client certificate used to authenticate to kubernetes apiserver is expiring in less than 7.0 days. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeclientcertificateexpiration + summary: Client certificate is about to expire. + expr: apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}job) histogram_quantile(0.01, sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}job, le) (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < 604800 + for: {{ dig "KubeClientCertificateExpiration" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeClientCertificateExpiration" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeClientCertificateExpiration | default false) }} + - alert: KubeClientCertificateExpiration + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: A client certificate used to authenticate to kubernetes apiserver is expiring in less than 24.0 hours. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeclientcertificateexpiration + summary: Client certificate is about to expire. + expr: apiserver_client_certificate_expiration_seconds_count{job="apiserver"} > 0 and on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}job) histogram_quantile(0.01, sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}job, le) (rate(apiserver_client_certificate_expiration_seconds_bucket{job="apiserver"}[5m]))) < 86400 + for: {{ dig "KubeClientCertificateExpiration" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeClientCertificateExpiration" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeAggregatedAPIErrors | default false) }} + - alert: KubeAggregatedAPIErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Kubernetes aggregated API {{`{{`}} $labels.name {{`}}`}}/{{`{{`}} $labels.namespace {{`}}`}} has reported errors. It has appeared unavailable {{`{{`}} $value | humanize {{`}}`}} times averaged over the past 10m. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeaggregatedapierrors + summary: Kubernetes aggregated API has reported errors. + expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}name, namespace, cluster)(increase(aggregator_unavailable_apiservice_total{job="apiserver"}[10m])) > 4 + labels: + severity: {{ dig "KubeAggregatedAPIErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeAggregatedAPIDown | default false) }} + - alert: KubeAggregatedAPIDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Kubernetes aggregated API {{`{{`}} $labels.name {{`}}`}}/{{`{{`}} $labels.namespace {{`}}`}} has been only {{`{{`}} $value | humanize {{`}}`}}% available over the last 10m. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeaggregatedapidown + summary: Kubernetes aggregated API is down. + expr: (1 - max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}name, namespace, cluster)(avg_over_time(aggregator_unavailable_apiservice{job="apiserver"}[10m]))) * 100 < 85 + for: {{ dig "KubeAggregatedAPIDown" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeAggregatedAPIDown" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if .Values.kubeApiServer.enabled }} +{{- if not (.Values.defaultRules.disabled.KubeAPIDown | default false) }} + - alert: KubeAPIDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: KubeAPI has disappeared from Prometheus target discovery. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapidown + summary: Target disappeared from Prometheus target discovery. + expr: absent(up{job="apiserver"} == 1) + for: {{ dig "KubeAPIDown" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeAPIDown" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeAPITerminatedRequests | default false) }} + - alert: KubeAPITerminatedRequests + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: The kubernetes apiserver has terminated {{`{{`}} $value | humanizePercentage {{`}}`}} of its incoming requests. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeapiterminatedrequests + summary: The kubernetes apiserver has terminated {{`{{`}} $value | humanizePercentage {{`}}`}} of its incoming requests. + expr: sum(rate(apiserver_request_terminations_total{job="apiserver"}[10m])) / ( sum(rate(apiserver_request_total{job="apiserver"}[10m])) + sum(rate(apiserver_request_terminations_total{job="apiserver"}[10m])) ) > 0.20 + for: {{ dig "KubeAPITerminatedRequests" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeAPITerminatedRequests" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-controller-manager.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-controller-manager.yaml new file mode 100644 index 0000000000..43b324596e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-controller-manager.yaml @@ -0,0 +1,57 @@ +{{- /* +Generated from 'kubernetes-system-controller-manager' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubeControllerManager }} +{{- if (include "exporter.kubeControllerManager.enabled" .)}} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-controller-manager" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-system-controller-manager + rules: +{{- if .Values.kubeControllerManager.enabled }} +{{- if not (.Values.defaultRules.disabled.KubeControllerManagerDown | default false) }} + - alert: KubeControllerManagerDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeControllerManager }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeControllerManager | indent 8 }} +{{- end }} + description: KubeControllerManager has disappeared from Prometheus target discovery. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubecontrollermanagerdown + summary: Target disappeared from Prometheus target discovery. + expr: absent(up{job="{{ include "exporter.kubeControllerManager.jobName" . }}"} == 1) + for: 15m + labels: + severity: {{ dig "KubeControllerManagerDown" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeControllerManager }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeControllerManager }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-kube-proxy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-kube-proxy.yaml new file mode 100644 index 0000000000..2000acece2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-kube-proxy.yaml @@ -0,0 +1,52 @@ +{{- /* +Generated from 'kubernetes-system-kube-proxy' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeProxy.enabled .Values.defaultRules.rules.kubeProxy }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-kube-proxy" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-system-kube-proxy + rules: +{{- if not (.Values.defaultRules.disabled.KubeProxyDown | default false) }} + - alert: KubeProxyDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeProxy }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeProxy | indent 8 }} +{{- end }} + description: KubeProxy has disappeared from Prometheus target discovery. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeproxydown + summary: Target disappeared from Prometheus target discovery. + expr: absent(up{job="{{ include "exporter.kubeProxy.jobName" . }}"} == 1) + for: 15m + labels: + severity: {{ dig "KubeProxyDown" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeProxy }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeProxy }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-kubelet.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-kubelet.yaml new file mode 100644 index 0000000000..d2cf87422d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-kubelet.yaml @@ -0,0 +1,379 @@ +{{- /* +Generated from 'kubernetes-system-kubelet' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesSystem }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-kubelet" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-system-kubelet + rules: +{{- if not (.Values.defaultRules.disabled.KubeNodeNotReady | default false) }} + - alert: KubeNodeNotReady + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: '{{`{{`}} $labels.node {{`}}`}} has been unready for more than 15 minutes.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubenodenotready + summary: Node is not ready. + expr: kube_node_status_condition{job="{{ $kubeStateMetricsJob }}",condition="Ready",status="true"} == 0 + for: {{ dig "KubeNodeNotReady" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeNodeNotReady" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeNodeUnreachable | default false) }} + - alert: KubeNodeUnreachable + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: '{{`{{`}} $labels.node {{`}}`}} is unreachable and some workloads may be rescheduled.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubenodeunreachable + summary: Node is unreachable. + expr: (kube_node_spec_taint{job="{{ $kubeStateMetricsJob }}",key="node.kubernetes.io/unreachable",effect="NoSchedule"} unless ignoring(key,value) kube_node_spec_taint{job="{{ $kubeStateMetricsJob }}",key=~"ToBeDeletedByClusterAutoscaler|cloud.google.com/impending-node-termination|aws-node-termination-handler/spot-itn"}) == 1 + for: {{ dig "KubeNodeUnreachable" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeNodeUnreachable" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletTooManyPods | default false) }} + - alert: KubeletTooManyPods + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Kubelet '{{`{{`}} $labels.node {{`}}`}}' is running at {{`{{`}} $value | humanizePercentage {{`}}`}} of its Pod capacity. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubelettoomanypods + summary: Kubelet is running at capacity. + expr: |- + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, node) ( + (kube_pod_status_phase{job="{{ $kubeStateMetricsJob }}",phase="Running"} == 1) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance,pod,namespace,cluster) group_left(node) topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}instance,pod,namespace,cluster) (1, kube_pod_info{job="{{ $kubeStateMetricsJob }}"}) + ) + / + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, node) ( + kube_node_status_capacity{job="{{ $kubeStateMetricsJob }}",resource="pods"} != 1 + ) > 0.95 + for: {{ dig "KubeletTooManyPods" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeletTooManyPods" "severity" "info" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeNodeReadinessFlapping | default false) }} + - alert: KubeNodeReadinessFlapping + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: The readiness status of node {{`{{`}} $labels.node {{`}}`}} has changed {{`{{`}} $value {{`}}`}} times in the last 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubenodereadinessflapping + summary: Node readiness status is flapping. + expr: sum(changes(kube_node_status_condition{job="{{ $kubeStateMetricsJob }}",status="true",condition="Ready"}[15m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, node) > 2 + for: {{ dig "KubeNodeReadinessFlapping" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeNodeReadinessFlapping" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletPlegDurationHigh | default false) }} + - alert: KubeletPlegDurationHigh + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: The Kubelet Pod Lifecycle Event Generator has a 99th percentile duration of {{`{{`}} $value {{`}}`}} seconds on node {{`{{`}} $labels.node {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletplegdurationhigh + summary: Kubelet Pod Lifecycle Event Generator is taking too long to relist. + expr: node_quantile:kubelet_pleg_relist_duration_seconds:histogram_quantile{quantile="0.99"} >= 10 + for: {{ dig "KubeletPlegDurationHigh" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeletPlegDurationHigh" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletPodStartUpLatencyHigh | default false) }} + - alert: KubeletPodStartUpLatencyHigh + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Kubelet Pod startup 99th percentile latency is {{`{{`}} $value {{`}}`}} seconds on node {{`{{`}} $labels.node {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletpodstartuplatencyhigh + summary: Kubelet Pod startup latency is too high. + expr: histogram_quantile(0.99, sum(rate(kubelet_pod_worker_duration_seconds_bucket{job="{{ include "exporter.kubelet.jobName" . }}", metrics_path="/metrics"}[5m])) by (cluster, instance, le)) * on(cluster, instance) group_left(node) kubelet_node_name{job="{{ include "exporter.kubelet.jobName" . }}", metrics_path="/metrics"} > 60 + for: 15m + labels: + severity: {{ dig "KubeletPodStartUpLatencyHigh" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletClientCertificateExpiration | default false) }} + - alert: KubeletClientCertificateExpiration + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Client certificate for Kubelet on node {{`{{`}} $labels.node {{`}}`}} expires in {{`{{`}} $value | humanizeDuration {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletclientcertificateexpiration + summary: Kubelet client certificate is about to expire. + expr: kubelet_certificate_manager_client_ttl_seconds < 604800 + labels: + severity: {{ dig "KubeletClientCertificateExpiration" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletClientCertificateExpiration | default false) }} + - alert: KubeletClientCertificateExpiration + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Client certificate for Kubelet on node {{`{{`}} $labels.node {{`}}`}} expires in {{`{{`}} $value | humanizeDuration {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletclientcertificateexpiration + summary: Kubelet client certificate is about to expire. + expr: kubelet_certificate_manager_client_ttl_seconds < 86400 + labels: + severity: {{ dig "KubeletClientCertificateExpiration" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletServerCertificateExpiration | default false) }} + - alert: KubeletServerCertificateExpiration + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Server certificate for Kubelet on node {{`{{`}} $labels.node {{`}}`}} expires in {{`{{`}} $value | humanizeDuration {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletservercertificateexpiration + summary: Kubelet server certificate is about to expire. + expr: kubelet_certificate_manager_server_ttl_seconds < 604800 + labels: + severity: {{ dig "KubeletServerCertificateExpiration" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletServerCertificateExpiration | default false) }} + - alert: KubeletServerCertificateExpiration + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Server certificate for Kubelet on node {{`{{`}} $labels.node {{`}}`}} expires in {{`{{`}} $value | humanizeDuration {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletservercertificateexpiration + summary: Kubelet server certificate is about to expire. + expr: kubelet_certificate_manager_server_ttl_seconds < 86400 + labels: + severity: {{ dig "KubeletServerCertificateExpiration" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletClientCertificateRenewalErrors | default false) }} + - alert: KubeletClientCertificateRenewalErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Kubelet on node {{`{{`}} $labels.node {{`}}`}} has failed to renew its client certificate ({{`{{`}} $value | humanize {{`}}`}} errors in the last 5 minutes). + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletclientcertificaterenewalerrors + summary: Kubelet has failed to renew its client certificate. + expr: increase(kubelet_certificate_manager_client_expiration_renew_errors[5m]) > 0 + for: {{ dig "KubeletClientCertificateRenewalErrors" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeletClientCertificateRenewalErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeletServerCertificateRenewalErrors | default false) }} + - alert: KubeletServerCertificateRenewalErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Kubelet on node {{`{{`}} $labels.node {{`}}`}} has failed to renew its server certificate ({{`{{`}} $value | humanize {{`}}`}} errors in the last 5 minutes). + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletservercertificaterenewalerrors + summary: Kubelet has failed to renew its server certificate. + expr: increase(kubelet_server_expiration_renew_errors[5m]) > 0 + for: {{ dig "KubeletServerCertificateRenewalErrors" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeletServerCertificateRenewalErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if (include "exporter.kubelet.enabled" .)}} +{{- if not (.Values.defaultRules.disabled.KubeletDown | default false) }} + - alert: KubeletDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Kubelet has disappeared from Prometheus target discovery. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeletdown + summary: Target disappeared from Prometheus target discovery. + expr: absent(up{job="{{ include "exporter.kubelet.jobName" . }}", metrics_path="/metrics"} == 1) + for: 15m + labels: + severity: {{ dig "KubeletDown" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-scheduler.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-scheduler.yaml new file mode 100644 index 0000000000..d32f15139d --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system-scheduler.yaml @@ -0,0 +1,54 @@ +{{- /* +Generated from 'kubernetes-system-scheduler' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.kubeScheduler.enabled .Values.defaultRules.rules.kubeSchedulerAlerting }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system-scheduler" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-system-scheduler + rules: +{{- if .Values.kubeScheduler.enabled }} +{{- if not (.Values.defaultRules.disabled.KubeSchedulerDown | default false) }} + - alert: KubeSchedulerDown + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubeSchedulerAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubeSchedulerAlerting | indent 8 }} +{{- end }} + description: KubeScheduler has disappeared from Prometheus target discovery. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeschedulerdown + summary: Target disappeared from Prometheus target discovery. + expr: absent(up{job="{{ include "exporter.kubeScheduler.jobName" . }}"} == 1) + for: 15m + labels: + severity: {{ dig "KubeSchedulerDown" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubeSchedulerAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system.yaml new file mode 100644 index 0000000000..929a6f43bd --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/kubernetes-system.yaml @@ -0,0 +1,87 @@ +{{- /* +Generated from 'kubernetes-system' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.kubernetesSystem }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "kubernetes-system" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: kubernetes-system + rules: +{{- if not (.Values.defaultRules.disabled.KubeVersionMismatch | default false) }} + - alert: KubeVersionMismatch + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: There are {{`{{`}} $value {{`}}`}} different semantic versions of Kubernetes components running. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeversionmismatch + summary: Different semantic versions of Kubernetes components running. + expr: count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}git_version, cluster) (label_replace(kubernetes_build_info{job!~"kube-dns|coredns"},"git_version","$1","git_version","(v[0-9]*.[0-9]*).*"))) > 1 + for: {{ dig "KubeVersionMismatch" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeVersionMismatch" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.KubeClientErrors | default false) }} + - alert: KubeClientErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.kubernetesSystem | indent 8 }} +{{- end }} + description: Kubernetes API server client '{{`{{`}} $labels.job {{`}}`}}/{{`{{`}} $labels.instance {{`}}`}}' is experiencing {{`{{`}} $value | humanizePercentage {{`}}`}} errors.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/kubernetes/kubeclienterrors + summary: Kubernetes API server client is experiencing errors. + expr: |- + (sum(rate(rest_client_requests_total{job="apiserver",code=~"5.."}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance, job, namespace) + / + sum(rate(rest_client_requests_total{job="apiserver"}[5m])) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance, job, namespace)) + > 0.01 + for: {{ dig "KubeClientErrors" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "KubeClientErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.kubernetesSystem }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-exporter.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-exporter.rules.yaml new file mode 100644 index 0000000000..aeaa80231c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-exporter.rules.yaml @@ -0,0 +1,188 @@ +{{- /* +Generated from 'node-exporter.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.nodeExporterRecording }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "node-exporter.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: node-exporter.rules + rules: + - expr: |- + count without (cpu, mode) ( + node_cpu_seconds_total{job="node-exporter",mode="idle"} + ) + record: instance:node_num_cpu:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + 1 - avg without (cpu) ( + sum without (mode) (rate(node_cpu_seconds_total{job="node-exporter", mode=~"idle|iowait|steal"}[5m])) + ) + record: instance:node_cpu_utilisation:rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + ( + node_load1{job="node-exporter"} + / + instance:node_num_cpu:sum{job="node-exporter"} + ) + record: instance:node_load1_per_cpu:ratio + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + 1 - ( + ( + node_memory_MemAvailable_bytes{job="node-exporter"} + or + ( + node_memory_Buffers_bytes{job="node-exporter"} + + + node_memory_Cached_bytes{job="node-exporter"} + + + node_memory_MemFree_bytes{job="node-exporter"} + + + node_memory_Slab_bytes{job="node-exporter"} + ) + ) + / + node_memory_MemTotal_bytes{job="node-exporter"} + ) + record: instance:node_memory_utilisation:ratio + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: rate(node_vmstat_pgmajfault{job="node-exporter"}[5m]) + record: instance:node_vmstat_pgmajfault:rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: rate(node_disk_io_time_seconds_total{job="node-exporter", device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)"}[5m]) + record: instance_device:node_disk_io_time_seconds:rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: rate(node_disk_io_time_weighted_seconds_total{job="node-exporter", device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)"}[5m]) + record: instance_device:node_disk_io_time_weighted_seconds:rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum without (device) ( + rate(node_network_receive_bytes_total{job="node-exporter", device!="lo"}[5m]) + ) + record: instance:node_network_receive_bytes_excluding_lo:rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum without (device) ( + rate(node_network_transmit_bytes_total{job="node-exporter", device!="lo"}[5m]) + ) + record: instance:node_network_transmit_bytes_excluding_lo:rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum without (device) ( + rate(node_network_receive_drop_total{job="node-exporter", device!="lo"}[5m]) + ) + record: instance:node_network_receive_drop_excluding_lo:rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum without (device) ( + rate(node_network_transmit_drop_total{job="node-exporter", device!="lo"}[5m]) + ) + record: instance:node_network_transmit_drop_excluding_lo:rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterRecording }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-exporter.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-exporter.yaml new file mode 100644 index 0000000000..80bfd9bf36 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-exporter.yaml @@ -0,0 +1,801 @@ +{{- /* +Generated from 'node-exporter' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.nodeExporterAlerting }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "node-exporter" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: node-exporter + rules: +{{- if not (.Values.defaultRules.disabled.NodeFilesystemSpaceFillingUp | default false) }} + - alert: NodeFilesystemSpaceFillingUp + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Filesystem on {{`{{`}} $labels.device {{`}}`}}, mounted on {{`{{`}} $labels.mountpoint {{`}}`}}, at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available space left and is filling up. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemspacefillingup + summary: Filesystem is predicted to run out of space within the next 24 hours. + expr: |- + ( + node_filesystem_avail_bytes{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 15 + and + predict_linear(node_filesystem_avail_bytes{job="node-exporter",fstype!="",mountpoint!=""}[6h], 24*60*60) < 0 + and + node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0 + ) + for: {{ dig "NodeFilesystemSpaceFillingUp" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFilesystemSpaceFillingUp" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFilesystemSpaceFillingUp | default false) }} + - alert: NodeFilesystemSpaceFillingUp + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Filesystem on {{`{{`}} $labels.device {{`}}`}}, mounted on {{`{{`}} $labels.mountpoint {{`}}`}}, at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available space left and is filling up fast. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemspacefillingup + summary: Filesystem is predicted to run out of space within the next 4 hours. + expr: |- + ( + node_filesystem_avail_bytes{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 10 + and + predict_linear(node_filesystem_avail_bytes{job="node-exporter",fstype!="",mountpoint!=""}[6h], 4*60*60) < 0 + and + node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0 + ) + for: {{ dig "NodeFilesystemSpaceFillingUp" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFilesystemSpaceFillingUp" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFilesystemAlmostOutOfSpace | default false) }} + - alert: NodeFilesystemAlmostOutOfSpace + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Filesystem on {{`{{`}} $labels.device {{`}}`}}, mounted on {{`{{`}} $labels.mountpoint {{`}}`}}, at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available space left. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemalmostoutofspace + summary: Filesystem has less than 5% space left. + expr: |- + ( + node_filesystem_avail_bytes{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 5 + and + node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0 + ) + for: {{ dig "NodeFilesystemAlmostOutOfSpace" "for" "30m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFilesystemAlmostOutOfSpace" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFilesystemAlmostOutOfSpace | default false) }} + - alert: NodeFilesystemAlmostOutOfSpace + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Filesystem on {{`{{`}} $labels.device {{`}}`}}, mounted on {{`{{`}} $labels.mountpoint {{`}}`}}, at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available space left. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemalmostoutofspace + summary: Filesystem has less than 3% space left. + expr: |- + ( + node_filesystem_avail_bytes{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_size_bytes{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 3 + and + node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0 + ) + for: {{ dig "NodeFilesystemAlmostOutOfSpace" "for" "30m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFilesystemAlmostOutOfSpace" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFilesystemFilesFillingUp | default false) }} + - alert: NodeFilesystemFilesFillingUp + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Filesystem on {{`{{`}} $labels.device {{`}}`}}, mounted on {{`{{`}} $labels.mountpoint {{`}}`}}, at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available inodes left and is filling up. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemfilesfillingup + summary: Filesystem is predicted to run out of inodes within the next 24 hours. + expr: |- + ( + node_filesystem_files_free{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_files{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 40 + and + predict_linear(node_filesystem_files_free{job="node-exporter",fstype!="",mountpoint!=""}[6h], 24*60*60) < 0 + and + node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0 + ) + for: {{ dig "NodeFilesystemFilesFillingUp" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFilesystemFilesFillingUp" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFilesystemFilesFillingUp | default false) }} + - alert: NodeFilesystemFilesFillingUp + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Filesystem on {{`{{`}} $labels.device {{`}}`}}, mounted on {{`{{`}} $labels.mountpoint {{`}}`}}, at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available inodes left and is filling up fast. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemfilesfillingup + summary: Filesystem is predicted to run out of inodes within the next 4 hours. + expr: |- + ( + node_filesystem_files_free{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_files{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 20 + and + predict_linear(node_filesystem_files_free{job="node-exporter",fstype!="",mountpoint!=""}[6h], 4*60*60) < 0 + and + node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0 + ) + for: {{ dig "NodeFilesystemFilesFillingUp" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFilesystemFilesFillingUp" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFilesystemAlmostOutOfFiles | default false) }} + - alert: NodeFilesystemAlmostOutOfFiles + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Filesystem on {{`{{`}} $labels.device {{`}}`}}, mounted on {{`{{`}} $labels.mountpoint {{`}}`}}, at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available inodes left. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemalmostoutoffiles + summary: Filesystem has less than 5% inodes left. + expr: |- + ( + node_filesystem_files_free{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_files{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 5 + and + node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0 + ) + for: {{ dig "NodeFilesystemAlmostOutOfFiles" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFilesystemAlmostOutOfFiles" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFilesystemAlmostOutOfFiles | default false) }} + - alert: NodeFilesystemAlmostOutOfFiles + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Filesystem on {{`{{`}} $labels.device {{`}}`}}, mounted on {{`{{`}} $labels.mountpoint {{`}}`}}, at {{`{{`}} $labels.instance {{`}}`}} has only {{`{{`}} printf "%.2f" $value {{`}}`}}% available inodes left. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefilesystemalmostoutoffiles + summary: Filesystem has less than 3% inodes left. + expr: |- + ( + node_filesystem_files_free{job="node-exporter",fstype!="",mountpoint!=""} / node_filesystem_files{job="node-exporter",fstype!="",mountpoint!=""} * 100 < 3 + and + node_filesystem_readonly{job="node-exporter",fstype!="",mountpoint!=""} == 0 + ) + for: {{ dig "NodeFilesystemAlmostOutOfFiles" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFilesystemAlmostOutOfFiles" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeNetworkReceiveErrs | default false) }} + - alert: NodeNetworkReceiveErrs + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: '{{`{{`}} $labels.instance {{`}}`}} interface {{`{{`}} $labels.device {{`}}`}} has encountered {{`{{`}} printf "%.0f" $value {{`}}`}} receive errors in the last two minutes.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodenetworkreceiveerrs + summary: Network interface is reporting many receive errors. + expr: rate(node_network_receive_errs_total{job="node-exporter"}[2m]) / rate(node_network_receive_packets_total{job="node-exporter"}[2m]) > 0.01 + for: {{ dig "NodeNetworkReceiveErrs" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeNetworkReceiveErrs" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeNetworkTransmitErrs | default false) }} + - alert: NodeNetworkTransmitErrs + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: '{{`{{`}} $labels.instance {{`}}`}} interface {{`{{`}} $labels.device {{`}}`}} has encountered {{`{{`}} printf "%.0f" $value {{`}}`}} transmit errors in the last two minutes.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodenetworktransmiterrs + summary: Network interface is reporting many transmit errors. + expr: rate(node_network_transmit_errs_total{job="node-exporter"}[2m]) / rate(node_network_transmit_packets_total{job="node-exporter"}[2m]) > 0.01 + for: {{ dig "NodeNetworkTransmitErrs" "for" "1h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeNetworkTransmitErrs" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeHighNumberConntrackEntriesUsed | default false) }} + - alert: NodeHighNumberConntrackEntriesUsed + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of conntrack entries are used.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodehighnumberconntrackentriesused + summary: Number of conntrack are getting close to the limit. + expr: (node_nf_conntrack_entries{job="node-exporter"} / node_nf_conntrack_entries_limit) > 0.75 + labels: + severity: {{ dig "NodeHighNumberConntrackEntriesUsed" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeTextFileCollectorScrapeError | default false) }} + - alert: NodeTextFileCollectorScrapeError + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Node Exporter text file collector on {{`{{`}} $labels.instance {{`}}`}} failed to scrape. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodetextfilecollectorscrapeerror + summary: Node Exporter text file collector failed to scrape. + expr: node_textfile_scrape_error{job="node-exporter"} == 1 + labels: + severity: {{ dig "NodeTextFileCollectorScrapeError" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeClockSkewDetected | default false) }} + - alert: NodeClockSkewDetected + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Clock at {{`{{`}} $labels.instance {{`}}`}} is out of sync by more than 0.05s. Ensure NTP is configured correctly on this host. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodeclockskewdetected + summary: Clock skew detected. + expr: |- + ( + node_timex_offset_seconds{job="node-exporter"} > 0.05 + and + deriv(node_timex_offset_seconds{job="node-exporter"}[5m]) >= 0 + ) + or + ( + node_timex_offset_seconds{job="node-exporter"} < -0.05 + and + deriv(node_timex_offset_seconds{job="node-exporter"}[5m]) <= 0 + ) + for: {{ dig "NodeClockSkewDetected" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeClockSkewDetected" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeClockNotSynchronising | default false) }} + - alert: NodeClockNotSynchronising + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Clock at {{`{{`}} $labels.instance {{`}}`}} is not synchronising. Ensure NTP is configured on this host. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodeclocknotsynchronising + summary: Clock not synchronising. + expr: |- + min_over_time(node_timex_sync_status{job="node-exporter"}[5m]) == 0 + and + node_timex_maxerror_seconds{job="node-exporter"} >= 16 + for: {{ dig "NodeClockNotSynchronising" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeClockNotSynchronising" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeRAIDDegraded | default false) }} + - alert: NodeRAIDDegraded + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: RAID array '{{`{{`}} $labels.device {{`}}`}}' at {{`{{`}} $labels.instance {{`}}`}} is in degraded state due to one or more disks failures. Number of spare drives is insufficient to fix issue automatically. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/noderaiddegraded + summary: RAID Array is degraded. + expr: node_md_disks_required{job="node-exporter",device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)"} - ignoring (state) (node_md_disks{state="active",job="node-exporter",device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)"}) > 0 + for: {{ dig "NodeRAIDDegraded" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeRAIDDegraded" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeRAIDDiskFailure | default false) }} + - alert: NodeRAIDDiskFailure + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: At least one device in RAID array at {{`{{`}} $labels.instance {{`}}`}} failed. Array '{{`{{`}} $labels.device {{`}}`}}' needs attention and possibly a disk swap. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/noderaiddiskfailure + summary: Failed device in RAID array. + expr: node_md_disks{state="failed",job="node-exporter",device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)"} > 0 + labels: + severity: {{ dig "NodeRAIDDiskFailure" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFileDescriptorLimit | default false) }} + - alert: NodeFileDescriptorLimit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: File descriptors limit at {{`{{`}} $labels.instance {{`}}`}} is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}%. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefiledescriptorlimit + summary: Kernel is predicted to exhaust file descriptors limit soon. + expr: |- + ( + node_filefd_allocated{job="node-exporter"} * 100 / node_filefd_maximum{job="node-exporter"} > 70 + ) + for: {{ dig "NodeFileDescriptorLimit" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFileDescriptorLimit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeFileDescriptorLimit | default false) }} + - alert: NodeFileDescriptorLimit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: File descriptors limit at {{`{{`}} $labels.instance {{`}}`}} is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}%. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodefiledescriptorlimit + summary: Kernel is predicted to exhaust file descriptors limit soon. + expr: |- + ( + node_filefd_allocated{job="node-exporter"} * 100 / node_filefd_maximum{job="node-exporter"} > 90 + ) + for: {{ dig "NodeFileDescriptorLimit" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeFileDescriptorLimit" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeCPUHighUsage | default false) }} + - alert: NodeCPUHighUsage + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: 'CPU usage at {{`{{`}} $labels.instance {{`}}`}} has been above 90% for the last 15 minutes, is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}%. + + ' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodecpuhighusage + summary: High CPU usage. + expr: sum without(mode) (avg without (cpu) (rate(node_cpu_seconds_total{job="node-exporter", mode!="idle"}[2m]))) * 100 > 90 + for: {{ dig "NodeCPUHighUsage" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeCPUHighUsage" "severity" "info" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeSystemSaturation | default false) }} + - alert: NodeSystemSaturation + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: 'System load per core at {{`{{`}} $labels.instance {{`}}`}} has been above 2 for the last 15 minutes, is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}. + + This might indicate this instance resources saturation and can cause it becoming unresponsive. + + ' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodesystemsaturation + summary: System saturated, load per core is very high. + expr: |- + node_load1{job="node-exporter"} + / count without (cpu, mode) (node_cpu_seconds_total{job="node-exporter", mode="idle"}) > 2 + for: {{ dig "NodeSystemSaturation" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeSystemSaturation" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeMemoryMajorPagesFaults | default false) }} + - alert: NodeMemoryMajorPagesFaults + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: 'Memory major pages are occurring at very high rate at {{`{{`}} $labels.instance {{`}}`}}, 500 major page faults per second for the last 15 minutes, is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}. + + Please check that there is enough memory available at this instance. + + ' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodememorymajorpagesfaults + summary: Memory major page faults are occurring at very high rate. + expr: rate(node_vmstat_pgmajfault{job="node-exporter"}[5m]) > 500 + for: {{ dig "NodeMemoryMajorPagesFaults" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeMemoryMajorPagesFaults" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeMemoryHighUtilization | default false) }} + - alert: NodeMemoryHighUtilization + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: 'Memory is filling up at {{`{{`}} $labels.instance {{`}}`}}, has been above 90% for the last 15 minutes, is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}%. + + ' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodememoryhighutilization + summary: Host is running out of memory. + expr: 100 - (node_memory_MemAvailable_bytes{job="node-exporter"} / node_memory_MemTotal_bytes{job="node-exporter"} * 100) > 90 + for: {{ dig "NodeMemoryHighUtilization" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeMemoryHighUtilization" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeDiskIOSaturation | default false) }} + - alert: NodeDiskIOSaturation + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: 'Disk IO queue (aqu-sq) is high on {{`{{`}} $labels.device {{`}}`}} at {{`{{`}} $labels.instance {{`}}`}}, has been above 10 for the last 30 minutes, is currently at {{`{{`}} printf "%.2f" $value {{`}}`}}. + + This symptom might indicate disk saturation. + + ' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodediskiosaturation + summary: Disk IO queue is high. + expr: rate(node_disk_io_time_weighted_seconds_total{job="node-exporter", device=~"(/dev/)?(mmcblk.p.+|nvme.+|rbd.+|sd.+|vd.+|xvd.+|dm-.+|md.+|dasd.+)"}[5m]) > 10 + for: {{ dig "NodeDiskIOSaturation" "for" "30m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeDiskIOSaturation" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeSystemdServiceFailed | default false) }} + - alert: NodeSystemdServiceFailed + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Systemd service {{`{{`}} $labels.name {{`}}`}} has entered failed state at {{`{{`}} $labels.instance {{`}}`}} + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodesystemdservicefailed + summary: Systemd service has entered failed state. + expr: node_systemd_unit_state{job="node-exporter", state="failed"} == 1 + for: {{ dig "NodeSystemdServiceFailed" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeSystemdServiceFailed" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.NodeBondingDegraded | default false) }} + - alert: NodeBondingDegraded + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.nodeExporterAlerting | indent 8 }} +{{- end }} + description: Bonding interface {{`{{`}} $labels.master {{`}}`}} on {{`{{`}} $labels.instance {{`}}`}} is in degraded state due to one or more slave failures. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/node/nodebondingdegraded + summary: Bonding interface is degraded + expr: (node_bonding_slaves - node_bonding_active) != 0 + for: {{ dig "NodeBondingDegraded" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeBondingDegraded" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.nodeExporterAlerting }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-network.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-network.yaml new file mode 100644 index 0000000000..16690ee313 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node-network.yaml @@ -0,0 +1,55 @@ +{{- /* +Generated from 'node-network' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.network }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "node-network" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: node-network + rules: +{{- if not (.Values.defaultRules.disabled.NodeNetworkInterfaceFlapping | default false) }} + - alert: NodeNetworkInterfaceFlapping + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.network }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.network | indent 8 }} +{{- end }} + description: Network interface "{{`{{`}} $labels.device {{`}}`}}" changing its up status often on node-exporter {{`{{`}} $labels.namespace {{`}}`}}/{{`{{`}} $labels.pod {{`}}`}} + runbook_url: {{ .Values.defaultRules.runbookUrl }}/general/nodenetworkinterfaceflapping + summary: Network interface is often changing its status + expr: changes(node_network_up{job="node-exporter",device!~"veth.+"}[2m]) > 2 + for: {{ dig "NodeNetworkInterfaceFlapping" "for" "2m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "NodeNetworkInterfaceFlapping" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.network }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.network }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node.rules.yaml new file mode 100644 index 0000000000..0bf9b8653e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/node.rules.yaml @@ -0,0 +1,109 @@ +{{- /* +Generated from 'node.rules' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.node }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "node.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: node.rules + rules: + - expr: |- + topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) (1, + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, node, namespace, pod) ( + label_replace(kube_pod_info{job="{{ $kubeStateMetricsJob }}",node!=""}, "pod", "$1", "pod", "(.*)") + )) + record: 'node_namespace_pod:kube_pod_info:' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.node }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.node }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, node) ( + node_cpu_seconds_total{mode="idle",job="node-exporter"} + * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) group_left(node) + topk by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod) (1, node_namespace_pod:kube_pod_info:) + ) + record: node:node_num_cpu:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.node }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.node }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum( + node_memory_MemAvailable_bytes{job="node-exporter"} or + ( + node_memory_Buffers_bytes{job="node-exporter"} + + node_memory_Cached_bytes{job="node-exporter"} + + node_memory_MemFree_bytes{job="node-exporter"} + + node_memory_Slab_bytes{job="node-exporter"} + ) + ) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) + record: :node_memory_MemAvailable_bytes:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.node }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.node }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + avg by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, node) ( + sum without (mode) ( + rate(node_cpu_seconds_total{mode!="idle",mode!="iowait",mode!="steal",job="node-exporter"}[5m]) + ) + ) + record: node:node_cpu_utilization:ratio_rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.node }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.node }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + avg by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) ( + node:node_cpu_utilization:ratio_rate5m + ) + record: cluster:node_cpu:ratio_rate5m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.node }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.node }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/prometheus-operator.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/prometheus-operator.yaml new file mode 100644 index 0000000000..cb5c495877 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/prometheus-operator.yaml @@ -0,0 +1,253 @@ +{{- /* +Generated from 'prometheus-operator' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.prometheusOperator }} +{{- $operatorJob := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "operator" }} +{{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus-operator" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: prometheus-operator + rules: +{{- if not (.Values.defaultRules.disabled.PrometheusOperatorListErrors | default false) }} + - alert: PrometheusOperatorListErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator | indent 8 }} +{{- end }} + description: Errors while performing List operations in controller {{`{{`}}$labels.controller{{`}}`}} in {{`{{`}}$labels.namespace{{`}}`}} namespace. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorlisterrors + summary: Errors while performing list operations in controller. + expr: (sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (rate(prometheus_operator_list_operations_failed_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[10m])) / sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (rate(prometheus_operator_list_operations_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[10m]))) > 0.4 + for: {{ dig "PrometheusOperatorListErrors" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOperatorListErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusOperatorWatchErrors | default false) }} + - alert: PrometheusOperatorWatchErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator | indent 8 }} +{{- end }} + description: Errors while performing watch operations in controller {{`{{`}}$labels.controller{{`}}`}} in {{`{{`}}$labels.namespace{{`}}`}} namespace. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorwatcherrors + summary: Errors while performing watch operations in controller. + expr: (sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (rate(prometheus_operator_watch_operations_failed_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m])) / sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (rate(prometheus_operator_watch_operations_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]))) > 0.4 + for: {{ dig "PrometheusOperatorWatchErrors" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOperatorWatchErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusOperatorSyncFailed | default false) }} + - alert: PrometheusOperatorSyncFailed + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator | indent 8 }} +{{- end }} + description: Controller {{`{{`}} $labels.controller {{`}}`}} in {{`{{`}} $labels.namespace {{`}}`}} namespace fails to reconcile {{`{{`}} $value {{`}}`}} objects. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorsyncfailed + summary: Last controller reconciliation failed + expr: min_over_time(prometheus_operator_syncs{status="failed",job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusOperatorSyncFailed" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOperatorSyncFailed" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusOperatorReconcileErrors | default false) }} + - alert: PrometheusOperatorReconcileErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator | indent 8 }} +{{- end }} + description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of reconciling operations failed for {{`{{`}} $labels.controller {{`}}`}} controller in {{`{{`}} $labels.namespace {{`}}`}} namespace.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorreconcileerrors + summary: Errors while reconciling objects. + expr: (sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (rate(prometheus_operator_reconcile_errors_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]))) / (sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (rate(prometheus_operator_reconcile_operations_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]))) > 0.1 + for: {{ dig "PrometheusOperatorReconcileErrors" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOperatorReconcileErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusOperatorStatusUpdateErrors | default false) }} + - alert: PrometheusOperatorStatusUpdateErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator | indent 8 }} +{{- end }} + description: '{{`{{`}} $value | humanizePercentage {{`}}`}} of status update operations failed for {{`{{`}} $labels.controller {{`}}`}} controller in {{`{{`}} $labels.namespace {{`}}`}} namespace.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorstatusupdateerrors + summary: Errors while updating objects status. + expr: (sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (rate(prometheus_operator_status_update_errors_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]))) / (sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (rate(prometheus_operator_status_update_operations_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]))) > 0.1 + for: {{ dig "PrometheusOperatorStatusUpdateErrors" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOperatorStatusUpdateErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusOperatorNodeLookupErrors | default false) }} + - alert: PrometheusOperatorNodeLookupErrors + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator | indent 8 }} +{{- end }} + description: Errors while reconciling Prometheus in {{`{{`}} $labels.namespace {{`}}`}} Namespace. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatornodelookuperrors + summary: Errors while reconciling Prometheus. + expr: rate(prometheus_operator_node_address_lookup_errors_total{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]) > 0.1 + for: {{ dig "PrometheusOperatorNodeLookupErrors" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOperatorNodeLookupErrors" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusOperatorNotReady | default false) }} + - alert: PrometheusOperatorNotReady + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator | indent 8 }} +{{- end }} + description: Prometheus operator in {{`{{`}} $labels.namespace {{`}}`}} namespace isn't ready to reconcile {{`{{`}} $labels.controller {{`}}`}} resources. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatornotready + summary: Prometheus operator not ready + expr: min by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,controller,namespace) (max_over_time(prometheus_operator_ready{job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]) == 0) + for: {{ dig "PrometheusOperatorNotReady" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOperatorNotReady" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusOperatorRejectedResources | default false) }} + - alert: PrometheusOperatorRejectedResources + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheusOperator | indent 8 }} +{{- end }} + description: Prometheus operator in {{`{{`}} $labels.namespace {{`}}`}} namespace rejected {{`{{`}} printf "%0.0f" $value {{`}}`}} {{`{{`}} $labels.controller {{`}}`}}/{{`{{`}} $labels.resource {{`}}`}} resources. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus-operator/prometheusoperatorrejectedresources + summary: Resources rejected by Prometheus operator + expr: min_over_time(prometheus_operator_managed_resources{state="rejected",job="{{ $operatorJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusOperatorRejectedResources" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOperatorRejectedResources" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheusOperator }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/prometheus.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/prometheus.yaml new file mode 100644 index 0000000000..0cc617ff77 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/prometheus.yaml @@ -0,0 +1,735 @@ +{{- /* +Generated from 'prometheus' group from https://github.com/prometheus-operator/kube-prometheus.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.defaultRules.rules.prometheus }} +{{- $prometheusJob := printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus" }} +{{- $namespace := printf "%s" (include "kube-prometheus-stack.namespace" .) }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "prometheus" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: prometheus + rules: +{{- if not (.Values.defaultRules.disabled.PrometheusBadConfig | default false) }} + - alert: PrometheusBadConfig + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed to reload its configuration. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusbadconfig + summary: Failed Prometheus configuration reload. + expr: |- + # Without max_over_time, failed scrapes could create false negatives, see + # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details. + max_over_time(prometheus_config_last_reload_successful{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) == 0 + for: {{ dig "PrometheusBadConfig" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusBadConfig" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusSDRefreshFailure | default false) }} + - alert: PrometheusSDRefreshFailure + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed to refresh SD with mechanism {{`{{`}}$labels.mechanism{{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheussdrefreshfailure + summary: Failed Prometheus SD refresh. + expr: increase(prometheus_sd_refresh_failures_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[10m]) > 0 + for: {{ dig "PrometheusSDRefreshFailure" "for" "20m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusSDRefreshFailure" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusKubernetesListWatchFailures | default false) }} + - alert: PrometheusKubernetesListWatchFailures + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Kubernetes service discovery of Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is experiencing {{`{{`}} printf "%.0f" $value {{`}}`}} failures with LIST/WATCH requests to the Kubernetes API in the last 5 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheuskuberneteslistwatchfailures + summary: Requests in Kubernetes SD are failing. + expr: increase(prometheus_sd_kubernetes_failures_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusKubernetesListWatchFailures" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusKubernetesListWatchFailures" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusNotificationQueueRunningFull | default false) }} + - alert: PrometheusNotificationQueueRunningFull + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Alert notification queue of Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is running full. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusnotificationqueuerunningfull + summary: Prometheus alert notification queue predicted to run full in less than 30m. + expr: |- + # Without min_over_time, failed scrapes could create false negatives, see + # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details. + ( + predict_linear(prometheus_notifications_queue_length{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m], 60 * 30) + > + min_over_time(prometheus_notifications_queue_capacity{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) + ) + for: {{ dig "PrometheusNotificationQueueRunningFull" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusNotificationQueueRunningFull" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusErrorSendingAlertsToSomeAlertmanagers | default false) }} + - alert: PrometheusErrorSendingAlertsToSomeAlertmanagers + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: '{{`{{`}} printf "%.1f" $value {{`}}`}}% errors while sending alerts from Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} to Alertmanager {{`{{`}}$labels.alertmanager{{`}}`}}.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheuserrorsendingalertstosomealertmanagers + summary: Prometheus has encountered more than 1% errors sending alerts to a specific Alertmanager. + expr: |- + ( + rate(prometheus_notifications_errors_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) + / + rate(prometheus_notifications_sent_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) + ) + * 100 + > 1 + for: {{ dig "PrometheusErrorSendingAlertsToSomeAlertmanagers" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusErrorSendingAlertsToSomeAlertmanagers" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusNotConnectedToAlertmanagers | default false) }} + - alert: PrometheusNotConnectedToAlertmanagers + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is not connected to any Alertmanagers. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusnotconnectedtoalertmanagers + summary: Prometheus is not connected to any Alertmanagers. + expr: |- + # Without max_over_time, failed scrapes could create false negatives, see + # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details. + max_over_time(prometheus_notifications_alertmanagers_discovered{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) < 1 + for: {{ dig "PrometheusNotConnectedToAlertmanagers" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusNotConnectedToAlertmanagers" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusTSDBReloadsFailing | default false) }} + - alert: PrometheusTSDBReloadsFailing + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has detected {{`{{`}}$value | humanize{{`}}`}} reload failures over the last 3h. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheustsdbreloadsfailing + summary: Prometheus has issues reloading blocks from disk. + expr: increase(prometheus_tsdb_reloads_failures_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[3h]) > 0 + for: {{ dig "PrometheusTSDBReloadsFailing" "for" "4h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusTSDBReloadsFailing" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusTSDBCompactionsFailing | default false) }} + - alert: PrometheusTSDBCompactionsFailing + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has detected {{`{{`}}$value | humanize{{`}}`}} compaction failures over the last 3h. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheustsdbcompactionsfailing + summary: Prometheus has issues compacting blocks. + expr: increase(prometheus_tsdb_compactions_failed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[3h]) > 0 + for: {{ dig "PrometheusTSDBCompactionsFailing" "for" "4h" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusTSDBCompactionsFailing" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusNotIngestingSamples | default false) }} + - alert: PrometheusNotIngestingSamples + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is not ingesting samples. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusnotingestingsamples + summary: Prometheus is not ingesting samples. + expr: |- + ( + sum without(type) (rate(prometheus_tsdb_head_samples_appended_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])) <= 0 + and + ( + sum without(scrape_job) (prometheus_target_metadata_cache_entries{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}) > 0 + or + sum without(rule_group) (prometheus_rule_group_rules{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}) > 0 + ) + ) + for: {{ dig "PrometheusNotIngestingSamples" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusNotIngestingSamples" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusDuplicateTimestamps | default false) }} + - alert: PrometheusDuplicateTimestamps + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is dropping {{`{{`}} printf "%.4g" $value {{`}}`}} samples/s with different values but duplicated timestamp. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusduplicatetimestamps + summary: Prometheus is dropping samples with duplicate timestamps. + expr: rate(prometheus_target_scrapes_sample_duplicate_timestamp_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusDuplicateTimestamps" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusDuplicateTimestamps" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusOutOfOrderTimestamps | default false) }} + - alert: PrometheusOutOfOrderTimestamps + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} is dropping {{`{{`}} printf "%.4g" $value {{`}}`}} samples/s with timestamps arriving out of order. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusoutofordertimestamps + summary: Prometheus drops samples with out-of-order timestamps. + expr: rate(prometheus_target_scrapes_sample_out_of_order_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusOutOfOrderTimestamps" "for" "10m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusOutOfOrderTimestamps" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusRemoteStorageFailures | default false) }} + - alert: PrometheusRemoteStorageFailures + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} failed to send {{`{{`}} printf "%.1f" $value {{`}}`}}% of the samples to {{`{{`}} $labels.remote_name{{`}}`}}:{{`{{`}} $labels.url {{`}}`}} + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusremotestoragefailures + summary: Prometheus fails to send samples to remote storage. + expr: |- + ( + (rate(prometheus_remote_storage_failed_samples_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) or rate(prometheus_remote_storage_samples_failed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])) + / + ( + (rate(prometheus_remote_storage_failed_samples_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) or rate(prometheus_remote_storage_samples_failed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])) + + + (rate(prometheus_remote_storage_succeeded_samples_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) or rate(prometheus_remote_storage_samples_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m])) + ) + ) + * 100 + > 1 + for: {{ dig "PrometheusRemoteStorageFailures" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusRemoteStorageFailures" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusRemoteWriteBehind | default false) }} + - alert: PrometheusRemoteWriteBehind + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} remote write is {{`{{`}} printf "%.1f" $value {{`}}`}}s behind for {{`{{`}} $labels.remote_name{{`}}`}}:{{`{{`}} $labels.url {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusremotewritebehind + summary: Prometheus remote write is behind. + expr: |- + # Without max_over_time, failed scrapes could create false negatives, see + # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details. + ( + max_over_time(prometheus_remote_storage_highest_timestamp_in_seconds{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) + - ignoring(remote_name, url) group_right + max_over_time(prometheus_remote_storage_queue_highest_sent_timestamp_seconds{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) + ) + > 120 + for: {{ dig "PrometheusRemoteWriteBehind" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusRemoteWriteBehind" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusRemoteWriteDesiredShards | default false) }} + - alert: PrometheusRemoteWriteDesiredShards + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} remote write desired shards calculation wants to run {{`{{`}} $value {{`}}`}} shards for queue {{`{{`}} $labels.remote_name{{`}}`}}:{{`{{`}} $labels.url {{`}}`}}, which is more than the max of {{`{{`}} printf `prometheus_remote_storage_shards_max{instance="%s",job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}` $labels.instance | query | first | value {{`}}`}}. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusremotewritedesiredshards + summary: Prometheus remote write desired shards calculation wants to run more than configured max shards. + expr: |- + # Without max_over_time, failed scrapes could create false negatives, see + # https://www.robustperception.io/alerting-on-gauges-in-prometheus-2-0 for details. + ( + max_over_time(prometheus_remote_storage_shards_desired{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) + > + max_over_time(prometheus_remote_storage_shards_max{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) + ) + for: {{ dig "PrometheusRemoteWriteDesiredShards" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusRemoteWriteDesiredShards" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusRuleFailures | default false) }} + - alert: PrometheusRuleFailures + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed to evaluate {{`{{`}} printf "%.0f" $value {{`}}`}} rules in the last 5m. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusrulefailures + summary: Prometheus is failing rule evaluations. + expr: increase(prometheus_rule_evaluation_failures_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusRuleFailures" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusRuleFailures" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusMissingRuleEvaluations | default false) }} + - alert: PrometheusMissingRuleEvaluations + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has missed {{`{{`}} printf "%.0f" $value {{`}}`}} rule group evaluations in the last 5m. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusmissingruleevaluations + summary: Prometheus is missing rule evaluations due to slow rule group evaluation. + expr: increase(prometheus_rule_group_iterations_missed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusMissingRuleEvaluations" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusMissingRuleEvaluations" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusTargetLimitHit | default false) }} + - alert: PrometheusTargetLimitHit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has dropped {{`{{`}} printf "%.0f" $value {{`}}`}} targets because the number of targets exceeded the configured target_limit. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheustargetlimithit + summary: Prometheus has dropped targets because some scrape configs have exceeded the targets limit. + expr: increase(prometheus_target_scrape_pool_exceeded_target_limit_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusTargetLimitHit" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusTargetLimitHit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusLabelLimitHit | default false) }} + - alert: PrometheusLabelLimitHit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has dropped {{`{{`}} printf "%.0f" $value {{`}}`}} targets because some samples exceeded the configured label_limit, label_name_length_limit or label_value_length_limit. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheuslabellimithit + summary: Prometheus has dropped targets because some scrape configs have exceeded the labels limit. + expr: increase(prometheus_target_scrape_pool_exceeded_label_limits_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusLabelLimitHit" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusLabelLimitHit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusScrapeBodySizeLimitHit | default false) }} + - alert: PrometheusScrapeBodySizeLimitHit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed {{`{{`}} printf "%.0f" $value {{`}}`}} scrapes in the last 5m because some targets exceeded the configured body_size_limit. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusscrapebodysizelimithit + summary: Prometheus has dropped some targets that exceeded body size limit. + expr: increase(prometheus_target_scrapes_exceeded_body_size_limit_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusScrapeBodySizeLimitHit" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusScrapeBodySizeLimitHit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusScrapeSampleLimitHit | default false) }} + - alert: PrometheusScrapeSampleLimitHit + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} has failed {{`{{`}} printf "%.0f" $value {{`}}`}} scrapes in the last 5m because some targets exceeded the configured sample_limit. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheusscrapesamplelimithit + summary: Prometheus has failed scrapes that have exceeded the configured sample limit. + expr: increase(prometheus_target_scrapes_exceeded_sample_limit_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0 + for: {{ dig "PrometheusScrapeSampleLimitHit" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusScrapeSampleLimitHit" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusTargetSyncFailure | default false) }} + - alert: PrometheusTargetSyncFailure + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: '{{`{{`}} printf "%.0f" $value {{`}}`}} targets in Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} have failed to sync because invalid configuration was supplied.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheustargetsyncfailure + summary: Prometheus has failed to sync targets. + expr: increase(prometheus_target_sync_failed_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[30m]) > 0 + for: {{ dig "PrometheusTargetSyncFailure" "for" "5m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusTargetSyncFailure" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusHighQueryLoad | default false) }} + - alert: PrometheusHighQueryLoad + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} query API has less than 20% available capacity in its query engine for the last 15 minutes. + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheushighqueryload + summary: Prometheus is reaching its maximum capacity serving concurrent requests. + expr: avg_over_time(prometheus_engine_queries{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) / max_over_time(prometheus_engine_queries_concurrent_max{job="{{ $prometheusJob }}",namespace="{{ $namespace }}"}[5m]) > 0.8 + for: {{ dig "PrometheusHighQueryLoad" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusHighQueryLoad" "severity" "warning" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- if not (.Values.defaultRules.disabled.PrometheusErrorSendingAlertsToAnyAlertmanager | default false) }} + - alert: PrometheusErrorSendingAlertsToAnyAlertmanager + annotations: +{{- if .Values.defaultRules.additionalRuleAnnotations }} +{{ toYaml .Values.defaultRules.additionalRuleAnnotations | indent 8 }} +{{- end }} +{{- if .Values.defaultRules.additionalRuleGroupAnnotations.prometheus }} +{{ toYaml .Values.defaultRules.additionalRuleGroupAnnotations.prometheus | indent 8 }} +{{- end }} + description: '{{`{{`}} printf "%.1f" $value {{`}}`}}% minimum errors while sending alerts from Prometheus {{`{{`}}$labels.namespace{{`}}`}}/{{`{{`}}$labels.pod{{`}}`}} to any Alertmanager.' + runbook_url: {{ .Values.defaultRules.runbookUrl }}/prometheus/prometheuserrorsendingalertstoanyalertmanager + summary: Prometheus encounters more than 3% errors sending alerts to any Alertmanager. + expr: |- + min without (alertmanager) ( + rate(prometheus_notifications_errors_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}",alertmanager!~``}[5m]) + / + rate(prometheus_notifications_sent_total{job="{{ $prometheusJob }}",namespace="{{ $namespace }}",alertmanager!~``}[5m]) + ) + * 100 + > 3 + for: {{ dig "PrometheusErrorSendingAlertsToAnyAlertmanager" "for" "15m" .Values.customRules }} + {{- with .Values.defaultRules.keepFiringFor }} + keep_firing_for: "{{ . }}" + {{- end }} + labels: + severity: {{ dig "PrometheusErrorSendingAlertsToAnyAlertmanager" "severity" "critical" .Values.customRules }} + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.prometheus }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/windows.node.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/windows.node.rules.yaml new file mode 100644 index 0000000000..7c25553861 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/windows.node.rules.yaml @@ -0,0 +1,301 @@ +{{- /* +Generated from 'windows.node.rules' group from https://github.com/kubernetes-monitoring/kubernetes-mixin.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.windowsMonitoring.enabled .Values.defaultRules.rules.windows }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "windows.node.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: windows.node.rules + rules: + - expr: |- + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) ( + windows_system_system_up_time{job="windows-exporter"} + ) + record: node:windows_node:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + count by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) (sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance, core) ( + windows_cpu_time_total{job="windows-exporter"} + )) + record: node:windows_node_num_cpu:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: 1 - avg by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (rate(windows_cpu_time_total{job="windows-exporter",mode="idle"}[1m])) + record: :windows_node_cpu_utilisation:avg1m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + 1 - avg by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) ( + rate(windows_cpu_time_total{job="windows-exporter",mode="idle"}[1m]) + ) + record: node:windows_node_cpu_utilisation:avg1m + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + 1 - + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (windows_memory_available_bytes{job="windows-exporter"}) + / + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (windows_os_visible_memory_bytes{job="windows-exporter"}) + record: ':windows_node_memory_utilisation:' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (windows_memory_available_bytes{job="windows-exporter"} + windows_memory_cache_bytes{job="windows-exporter"}) + record: :windows_node_memory_MemFreeCached_bytes:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: (windows_memory_cache_bytes{job="windows-exporter"} + windows_memory_modified_page_list_bytes{job="windows-exporter"} + windows_memory_standby_cache_core_bytes{job="windows-exporter"} + windows_memory_standby_cache_normal_priority_bytes{job="windows-exporter"} + windows_memory_standby_cache_reserve_bytes{job="windows-exporter"}) + record: node:windows_node_memory_totalCached_bytes:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (windows_os_visible_memory_bytes{job="windows-exporter"}) + record: :windows_node_memory_MemTotal_bytes:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) ( + (windows_memory_available_bytes{job="windows-exporter"}) + ) + record: node:windows_node_memory_bytes_available:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) ( + windows_os_visible_memory_bytes{job="windows-exporter"} + ) + record: node:windows_node_memory_bytes_total:sum + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + (node:windows_node_memory_bytes_total:sum - node:windows_node_memory_bytes_available:sum) + / + scalar(sum(node:windows_node_memory_bytes_total:sum)) + record: node:windows_node_memory_utilisation:ratio + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: 1 - (node:windows_node_memory_bytes_available:sum / node:windows_node_memory_bytes_total:sum) + record: 'node:windows_node_memory_utilisation:' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: irate(windows_memory_swap_page_operations_total{job="windows-exporter"}[5m]) + record: node:windows_node_memory_swap_io_pages:irate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + avg by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (irate(windows_logical_disk_read_seconds_total{job="windows-exporter"}[1m]) + + irate(windows_logical_disk_write_seconds_total{job="windows-exporter"}[1m]) + ) + record: :windows_node_disk_utilisation:avg_irate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + avg by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) ( + (irate(windows_logical_disk_read_seconds_total{job="windows-exporter"}[1m]) + + irate(windows_logical_disk_write_seconds_total{job="windows-exporter"}[1m])) + ) + record: node:windows_node_disk_utilisation:avg_irate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster,instance,volume)( + (windows_logical_disk_size_bytes{job="windows-exporter"} + - windows_logical_disk_free_bytes{job="windows-exporter"}) + / windows_logical_disk_size_bytes{job="windows-exporter"} + ) + record: 'node:windows_node_filesystem_usage:' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance, volume) (windows_logical_disk_free_bytes{job="windows-exporter"} / windows_logical_disk_size_bytes{job="windows-exporter"}) + record: 'node:windows_node_filesystem_avail:' + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (irate(windows_net_bytes_total{job="windows-exporter"}[1m])) + record: :windows_node_net_utilisation:sum_irate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) ( + (irate(windows_net_bytes_total{job="windows-exporter"}[1m])) + ) + record: node:windows_node_net_utilisation:sum_irate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (irate(windows_net_packets_received_discarded_total{job="windows-exporter"}[1m])) + + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster) (irate(windows_net_packets_outbound_discarded_total{job="windows-exporter"}[1m])) + record: :windows_node_net_saturation:sum_irate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, instance) ( + (irate(windows_net_packets_received_discarded_total{job="windows-exporter"}[1m]) + + irate(windows_net_packets_outbound_discarded_total{job="windows-exporter"}[1m])) + ) + record: node:windows_node_net_saturation:sum_irate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/windows.pod.rules.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/windows.pod.rules.yaml new file mode 100644 index 0000000000..86340b5c05 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/rules-1.14/windows.pod.rules.yaml @@ -0,0 +1,158 @@ +{{- /* +Generated from 'windows.pod.rules' group from https://github.com/kubernetes-monitoring/kubernetes-mixin.git +Do not change in-place! In order to change this file first read following link: +https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/hack +*/ -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if and (semverCompare ">=1.14.0-0" $kubeTargetVersion) (semverCompare "<9.9.9-9" $kubeTargetVersion) .Values.defaultRules.create .Values.windowsMonitoring.enabled .Values.defaultRules.rules.windows }} +{{- $kubeStateMetricsJob := include "kube-prometheus-stack-kube-state-metrics.name" . }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" .) "windows.pod.rules" | trunc 63 | trimSuffix "-" }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.defaultRules.labels }} +{{ toYaml .Values.defaultRules.labels | indent 4 }} +{{- end }} +{{- if .Values.defaultRules.annotations }} + annotations: +{{ toYaml .Values.defaultRules.annotations | indent 4 }} +{{- end }} +spec: + groups: + - name: windows.pod.rules + rules: + - expr: windows_container_available{job="windows-exporter", container_id != ""} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container_id, cluster) group_left(container, pod, namespace) max(kube_pod_container_info{job="{{ $kubeStateMetricsJob }}", container_id != ""}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container, container_id, pod, namespace, cluster) + record: windows_pod_container_available + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: windows_container_cpu_usage_seconds_total{job="windows-exporter", container_id != ""} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container_id, cluster) group_left(container, pod, namespace) max(kube_pod_container_info{job="{{ $kubeStateMetricsJob }}", container_id != ""}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container, container_id, pod, namespace, cluster) + record: windows_container_total_runtime + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: windows_container_memory_usage_commit_bytes{job="windows-exporter", container_id != ""} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container_id, cluster) group_left(container, pod, namespace) max(kube_pod_container_info{job="{{ $kubeStateMetricsJob }}", container_id != ""}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container, container_id, pod, namespace, cluster) + record: windows_container_memory_usage + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: windows_container_memory_usage_private_working_set_bytes{job="windows-exporter", container_id != ""} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container_id, cluster) group_left(container, pod, namespace) max(kube_pod_container_info{job="{{ $kubeStateMetricsJob }}", container_id != ""}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container, container_id, pod, namespace, cluster) + record: windows_container_private_working_set_usage + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: windows_container_network_receive_bytes_total{job="windows-exporter", container_id != ""} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container_id, cluster) group_left(container, pod, namespace) max(kube_pod_container_info{job="{{ $kubeStateMetricsJob }}", container_id != ""}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container, container_id, pod, namespace, cluster) + record: windows_container_network_received_bytes_total + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: windows_container_network_transmit_bytes_total{job="windows-exporter", container_id != ""} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container_id, cluster) group_left(container, pod, namespace) max(kube_pod_container_info{job="{{ $kubeStateMetricsJob }}", container_id != ""}) by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container, container_id, pod, namespace, cluster) + record: windows_container_network_transmitted_bytes_total + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, container) ( + kube_pod_container_resource_requests{resource="memory",job="{{ $kubeStateMetricsJob }}"} + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container,pod,namespace,cluster) (windows_pod_container_available) + record: kube_pod_windows_container_resource_memory_request + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: kube_pod_container_resource_limits{resource="memory",job="{{ $kubeStateMetricsJob }}"} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container,pod,namespace,cluster) (windows_pod_container_available) + record: kube_pod_windows_container_resource_memory_limit + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + max by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, container) ( + kube_pod_container_resource_requests{resource="cpu",job="{{ $kubeStateMetricsJob }}"} + ) * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container,pod,namespace,cluster) (windows_pod_container_available) + record: kube_pod_windows_container_resource_cpu_cores_request + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: kube_pod_container_resource_limits{resource="cpu",job="{{ $kubeStateMetricsJob }}"} * on ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}container,pod,namespace,cluster) (windows_pod_container_available) + record: kube_pod_windows_container_resource_cpu_cores_limit + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + - expr: |- + sum by ({{ range $.Values.defaultRules.additionalAggregationLabels }}{{ . }},{{ end }}cluster, namespace, pod, container) ( + rate(windows_container_total_runtime{}[5m]) + ) + record: namespace_pod_container:windows_container_cpu_usage_seconds_total:sum_rate + {{- if or .Values.defaultRules.additionalRuleLabels .Values.defaultRules.additionalRuleGroupLabels.windows }} + labels: + {{- with .Values.defaultRules.additionalRuleLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.defaultRules.additionalRuleGroupLabels.windows }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/secret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/secret.yaml new file mode 100644 index 0000000000..e4a1e73c7b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/secret.yaml @@ -0,0 +1,15 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.prometheusSpec.thanos .Values.prometheus.prometheusSpec.thanos.objectStorageConfig}} +{{- if and .Values.prometheus.prometheusSpec.thanos.objectStorageConfig.secret (not .Values.prometheus.prometheusSpec.thanos.objectStorageConfig.existingSecret) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus + app.kubernetes.io/component: prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: + object-storage-configs.yaml: {{ toYaml .Values.prometheus.prometheusSpec.thanos.objectStorageConfig.secret | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/service.yaml new file mode 100644 index 0000000000..bfabebe7b9 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/service.yaml @@ -0,0 +1,84 @@ +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if .Values.prometheus.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus + self-monitor: {{ .Values.prometheus.serviceMonitor.selfMonitor | quote }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.prometheus.service.labels }} +{{ toYaml .Values.prometheus.service.labels | indent 4 }} +{{- end }} +{{- if .Values.prometheus.service.annotations }} + annotations: +{{ toYaml .Values.prometheus.service.annotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.prometheus.service.clusterIP }} + clusterIP: {{ .Values.prometheus.service.clusterIP }} +{{- end }} +{{- if .Values.prometheus.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.prometheus.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.prometheus.service.ipDualStack.ipFamilyPolicy }} +{{- end }} +{{- if .Values.prometheus.service.externalIPs }} + externalIPs: +{{ toYaml .Values.prometheus.service.externalIPs | indent 4 }} +{{- end }} +{{- if .Values.prometheus.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.prometheus.service.loadBalancerIP }} +{{- end }} +{{- if .Values.prometheus.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.prometheus.service.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} +{{- end }} +{{- if ne .Values.prometheus.service.type "ClusterIP" }} + externalTrafficPolicy: {{ .Values.prometheus.service.externalTrafficPolicy }} +{{- end }} + ports: + - name: {{ .Values.prometheus.prometheusSpec.portName }} + {{- if eq .Values.prometheus.service.type "NodePort" }} + nodePort: {{ .Values.prometheus.service.nodePort }} + {{- end }} + port: {{ .Values.prometheus.service.port }} + targetPort: {{ .Values.prometheus.service.targetPort }} + - name: reloader-web + {{- if semverCompare "> 1.20.0-0" $kubeTargetVersion }} + appProtocol: http + {{- end }} + port: {{ .Values.prometheus.service.reloaderWebPort }} + targetPort: reloader-web + {{- if .Values.prometheus.thanosIngress.enabled }} + - name: grpc + {{- if eq .Values.prometheus.service.type "NodePort" }} + nodePort: {{ .Values.prometheus.thanosIngress.nodePort }} + {{- end }} + port: {{ .Values.prometheus.thanosIngress.servicePort }} + targetPort: {{ .Values.prometheus.thanosIngress.servicePort }} + {{- end }} +{{- if .Values.prometheus.service.additionalPorts }} +{{ toYaml .Values.prometheus.service.additionalPorts | indent 2 }} +{{- end }} + publishNotReadyAddresses: {{ .Values.prometheus.service.publishNotReadyAddresses }} + selector: + {{- if .Values.prometheus.agentMode }} + app.kubernetes.io/name: prometheus-agent + {{- else }} + app.kubernetes.io/name: prometheus + {{- end }} + operator.prometheus.io/name: {{ template "kube-prometheus-stack.prometheus.crname" . }} +{{- if .Values.prometheus.service.sessionAffinity }} + sessionAffinity: {{ .Values.prometheus.service.sessionAffinity }} +{{- end }} +{{- if eq .Values.prometheus.service.sessionAffinity "ClientIP" }} + sessionAffinityConfig: + clientIP: + timeoutSeconds: {{ .Values.prometheus.service.sessionAffinityConfig.clientIP.timeoutSeconds }} +{{- end }} + type: "{{ .Values.prometheus.service.type }}" +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceThanosSidecar.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceThanosSidecar.yaml new file mode 100644 index 0000000000..87fae7b4f9 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceThanosSidecar.yaml @@ -0,0 +1,43 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.thanosService.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-discovery + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-thanos-discovery +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.prometheus.thanosService.labels }} +{{ toYaml .Values.prometheus.thanosService.labels | indent 4 }} +{{- end }} +{{- if .Values.prometheus.thanosService.annotations }} + annotations: +{{ toYaml .Values.prometheus.thanosService.annotations | indent 4 }} +{{- end }} +spec: + type: {{ .Values.prometheus.thanosService.type }} + clusterIP: {{ .Values.prometheus.thanosService.clusterIP }} +{{- if .Values.prometheus.thanosService.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.prometheus.thanosService.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.prometheus.thanosService.ipDualStack.ipFamilyPolicy }} +{{- end }} +{{- if ne .Values.prometheus.thanosService.type "ClusterIP" }} + externalTrafficPolicy: {{ .Values.prometheus.thanosService.externalTrafficPolicy }} +{{- end }} + ports: + - name: {{ .Values.prometheus.thanosService.portName }} + port: {{ .Values.prometheus.thanosService.port }} + targetPort: {{ .Values.prometheus.thanosService.targetPort }} + {{- if eq .Values.prometheus.thanosService.type "NodePort" }} + nodePort: {{ .Values.prometheus.thanosService.nodePort }} + {{- end }} + - name: {{ .Values.prometheus.thanosService.httpPortName }} + port: {{ .Values.prometheus.thanosService.httpPort }} + targetPort: {{ .Values.prometheus.thanosService.targetHttpPort }} + {{- if eq .Values.prometheus.thanosService.type "NodePort" }} + nodePort: {{ .Values.prometheus.thanosService.httpNodePort }} + {{- end }} + selector: + app.kubernetes.io/name: prometheus + operator.prometheus.io/name: {{ template "kube-prometheus-stack.prometheus.crname" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceThanosSidecarExternal.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceThanosSidecarExternal.yaml new file mode 100644 index 0000000000..453eed7f1b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceThanosSidecarExternal.yaml @@ -0,0 +1,46 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.thanosServiceExternal.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-external + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.prometheus.thanosServiceExternal.labels }} +{{ toYaml .Values.prometheus.thanosServiceExternal.labels | indent 4 }} +{{- end }} +{{- if .Values.prometheus.thanosServiceExternal.annotations }} + annotations: +{{ toYaml .Values.prometheus.thanosServiceExternal.annotations | indent 4 }} +{{- end }} +spec: + type: {{ .Values.prometheus.thanosServiceExternal.type }} +{{- if .Values.prometheus.thanosServiceExternal.loadBalancerIP }} + loadBalancerIP: {{ .Values.prometheus.thanosServiceExternal.loadBalancerIP }} +{{- end }} +{{- if .Values.prometheus.thanosServiceExternal.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.prometheus.thanosServiceExternal.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} +{{- end }} +{{- if ne .Values.prometheus.thanosServiceExternal.type "ClusterIP" }} + externalTrafficPolicy: {{ .Values.prometheus.thanosServiceExternal.externalTrafficPolicy }} +{{- end }} + ports: + - name: {{ .Values.prometheus.thanosServiceExternal.portName }} + port: {{ .Values.prometheus.thanosServiceExternal.port }} + targetPort: {{ .Values.prometheus.thanosServiceExternal.targetPort }} + {{- if eq .Values.prometheus.thanosServiceExternal.type "NodePort" }} + nodePort: {{ .Values.prometheus.thanosServiceExternal.nodePort }} + {{- end }} + - name: {{ .Values.prometheus.thanosServiceExternal.httpPortName }} + port: {{ .Values.prometheus.thanosServiceExternal.httpPort }} + targetPort: {{ .Values.prometheus.thanosServiceExternal.targetHttpPort }} + {{- if eq .Values.prometheus.thanosServiceExternal.type "NodePort" }} + nodePort: {{ .Values.prometheus.thanosServiceExternal.httpNodePort }} + {{- end }} + selector: + app.kubernetes.io/name: prometheus + operator.prometheus.io/name: {{ template "kube-prometheus-stack.prometheus.crname" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceaccount.yaml new file mode 100644 index 0000000000..e97b989bbd --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceaccount.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kube-prometheus-stack.prometheus.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus + app.kubernetes.io/name: {{ template "kube-prometheus-stack.name" . }}-prometheus + app.kubernetes.io/component: prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- if .Values.prometheus.serviceAccount.annotations }} + annotations: +{{ toYaml .Values.prometheus.serviceAccount.annotations | indent 4 }} +{{- end }} +automountServiceAccountToken: {{ .Values.prometheus.serviceAccount.automountServiceAccountToken }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{ include "kube-prometheus-stack.imagePullSecrets" . | trim | indent 2 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitor.yaml new file mode 100644 index 0000000000..a36f3e33ca --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitor.yaml @@ -0,0 +1,97 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.serviceMonitor.selfMonitor }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- with .Values.prometheus.serviceMonitor.additionalLabels }} +{{- toYaml . | nindent 4 }} +{{- end }} +spec: + {{- include "servicemonitor.scrapeLimits" .Values.prometheus.serviceMonitor | nindent 2 }} + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-prometheus + release: {{ $.Release.Name | quote }} + self-monitor: "true" + namespaceSelector: + matchNames: + - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }} + endpoints: + - port: {{ .Values.prometheus.prometheusSpec.portName }} + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.scheme }} + scheme: {{ .Values.prometheus.serviceMonitor.scheme }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.tlsConfig }} + tlsConfig: {{- toYaml .Values.prometheus.serviceMonitor.tlsConfig | nindent 6 }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.prometheus.serviceMonitor.bearerTokenFile }} + {{- end }} + path: "{{ trimSuffix "/" .Values.prometheus.prometheusSpec.routePrefix }}/metrics" + metricRelabelings: + {{- if .Values.prometheus.serviceMonitor.metricRelabelings }} + {{- tpl (toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 6) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.relabelings }} + relabelings: {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 6 }} + {{- end }} + - port: reloader-web + {{- if .Values.prometheus.serviceMonitor.interval }} + interval: {{ .Values.prometheus.serviceMonitor.interval }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.scheme }} + scheme: {{ .Values.prometheus.serviceMonitor.scheme }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.tlsConfig }} + tlsConfig: {{- toYaml .Values.prometheus.serviceMonitor.tlsConfig | nindent 6 }} + {{- end }} + path: "/metrics" + {{- if .Values.prometheus.serviceMonitor.metricRelabelings }} + metricRelabelings: {{- tpl (toYaml .Values.prometheus.serviceMonitor.metricRelabelings | nindent 6) . }} + {{- end }} + {{- if .Values.prometheus.serviceMonitor.relabelings }} + relabelings: {{- toYaml .Values.prometheus.serviceMonitor.relabelings | nindent 6 }} + {{- end }} + {{- range .Values.prometheus.serviceMonitor.additionalEndpoints }} + - port: {{ .port }} + {{- if or $.Values.prometheus.serviceMonitor.interval .interval }} + interval: {{ default $.Values.prometheus.serviceMonitor.interval .interval }} + {{- end }} + {{- if or $.Values.prometheus.serviceMonitor.proxyUrl .proxyUrl }} + proxyUrl: {{ default $.Values.prometheus.serviceMonitor.proxyUrl .proxyUrl }} + {{- end }} + {{- if or $.Values.prometheus.serviceMonitor.scheme .scheme }} + scheme: {{ default $.Values.prometheus.serviceMonitor.scheme .scheme }} + {{- end }} + {{- if or $.Values.prometheus.serviceMonitor.bearerTokenFile .bearerTokenFile }} + bearerTokenFile: {{ default $.Values.prometheus.serviceMonitor.bearerTokenFile .bearerTokenFile }} + {{- end }} + {{- if or $.Values.prometheus.serviceMonitor.tlsConfig .tlsConfig }} + tlsConfig: {{- default $.Values.prometheus.serviceMonitor.tlsConfig .tlsConfig | toYaml | nindent 6 }} + {{- end }} + path: {{ .path }} + {{- if or $.Values.prometheus.serviceMonitor.metricRelabelings .metricRelabelings }} + metricRelabelings: {{- tpl (default $.Values.prometheus.serviceMonitor.metricRelabelings .metricRelabelings | toYaml | nindent 6) . }} + {{- end }} + {{- if or $.Values.prometheus.serviceMonitor.relabelings .relabelings }} + relabelings: {{- default $.Values.prometheus.serviceMonitor.relabelings .relabelings | toYaml | nindent 6 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitorThanosSidecar.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitorThanosSidecar.yaml new file mode 100644 index 0000000000..0f70aabb58 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitorThanosSidecar.yaml @@ -0,0 +1,55 @@ +{{- if and .Values.prometheus.thanosService.enabled .Values.prometheus.thanosServiceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-thanos-sidecar + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-thanos-sidecar +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- with .Values.prometheus.thanosServiceMonitor.additionalLabels }} +{{- toYaml . | nindent 4 }} +{{- end }} +spec: + {{- include "servicemonitor.scrapeLimits" .Values.prometheus.thanosServiceMonitor | nindent 2 }} + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-thanos-discovery + release: {{ $.Release.Name | quote }} + namespaceSelector: + matchNames: + - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }} + endpoints: + - port: {{ .Values.prometheus.thanosService.httpPortName }} + {{- if .Values.prometheus.thanosServiceMonitor.interval }} + interval: {{ .Values.prometheus.thanosServiceMonitor.interval }} + {{- end }} + {{- if .Values.prometheus.thanosServiceMonitor.scheme }} + scheme: {{ .Values.prometheus.thanosServiceMonitor.scheme }} + {{- end }} + {{- if .Values.prometheus.thanosServiceMonitor.tlsConfig }} + tlsConfig: {{ toYaml .Values.prometheus.thanosServiceMonitor.tlsConfig | nindent 6 }} + {{- end }} + {{- if .Values.prometheus.thanosServiceMonitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.prometheus.thanosServiceMonitor.bearerTokenFile }} + {{- end }} + path: "/metrics" + metricRelabelings: + {{- if .Values.prometheus.thanosServiceMonitor.metricRelabelings}} + {{ tpl (toYaml .Values.prometheus.thanosServiceMonitor.metricRelabelings | indent 6) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.prometheus.thanosServiceMonitor.relabelings }} + relabelings: +{{ toYaml .Values.prometheus.thanosServiceMonitor.relabelings | indent 6 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitors.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitors.yaml new file mode 100644 index 0000000000..a7a301babc --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/servicemonitors.yaml @@ -0,0 +1,47 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.additionalServiceMonitors }} +apiVersion: v1 +kind: List +items: +{{- range .Values.prometheus.additionalServiceMonitors }} + - apiVersion: monitoring.coreos.com/v1 + kind: ServiceMonitor + metadata: + name: {{ .name }} + namespace: {{ template "kube-prometheus-stack.namespace" $ }} + labels: + app: {{ template "kube-prometheus-stack.name" $ }}-prometheus +{{ include "kube-prometheus-stack.labels" $ | indent 8 }} + {{- if .additionalLabels }} +{{ toYaml .additionalLabels | indent 8 }} + {{- end }} + spec: + {{- include "servicemonitor.scrapeLimits" . | nindent 6 }} + endpoints: +{{ toYaml .endpoints | indent 8 }} + {{- if .jobLabel }} + jobLabel: {{ .jobLabel }} + {{- end }} + {{- if .namespaceSelector }} + namespaceSelector: +{{ toYaml .namespaceSelector | indent 8 }} + {{- end }} + selector: +{{ toYaml .selector | indent 8 }} + {{- if .targetLabels }} + targetLabels: +{{ toYaml .targetLabels | indent 8 }} + {{- end }} + {{- if .podTargetLabels }} + podTargetLabels: +{{ toYaml .podTargetLabels | indent 8 }} + {{- end }} + {{- if .metricRelabelings }} + metricRelabelings: +{{ toYaml .metricRelabelings | indent 8 }} + {{- end }} + {{- if .relabelings }} + relabelings: +{{ toYaml .relabelings | indent 8 }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceperreplica.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceperreplica.yaml new file mode 100644 index 0000000000..3a88b2df34 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/prometheus/serviceperreplica.yaml @@ -0,0 +1,58 @@ +{{- if and .Values.prometheus.enabled .Values.prometheus.servicePerReplica.enabled }} +{{- $count := .Values.prometheus.prometheusSpec.replicas | int -}} +{{- $serviceValues := .Values.prometheus.servicePerReplica -}} +apiVersion: v1 +kind: List +metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-serviceperreplica + namespace: {{ template "kube-prometheus-stack.namespace" . }} +items: +{{- range $i, $e := until $count }} + - apiVersion: v1 + kind: Service + metadata: + name: {{ include "kube-prometheus-stack.fullname" $ }}-prometheus-{{ $i }} + namespace: {{ template "kube-prometheus-stack.namespace" $ }} + labels: + app: {{ include "kube-prometheus-stack.name" $ }}-prometheus +{{ include "kube-prometheus-stack.labels" $ | indent 8 }} + {{- if $serviceValues.annotations }} + annotations: +{{ toYaml $serviceValues.annotations | indent 8 }} + {{- end }} + spec: + {{- if $serviceValues.clusterIP }} + clusterIP: {{ $serviceValues.clusterIP }} + {{- end }} + {{- if $serviceValues.ipDualStack.enabled }} + ipFamilies: {{ toYaml $serviceValues.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ $serviceValues.ipDualStack.ipFamilyPolicy }} + {{- end }} + {{- if $serviceValues.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := $serviceValues.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} + {{- end }} + {{- if ne $serviceValues.type "ClusterIP" }} + externalTrafficPolicy: {{ $serviceValues.externalTrafficPolicy }} + {{- end }} + ports: + - name: {{ $.Values.prometheus.prometheusSpec.portName }} + {{- if eq $serviceValues.type "NodePort" }} + nodePort: {{ $serviceValues.nodePort }} + {{- end }} + port: {{ $serviceValues.port }} + targetPort: {{ $serviceValues.targetPort }} + selector: + {{- if $.Values.prometheus.agentMode }} + app.kubernetes.io/name: prometheus-agent + statefulset.kubernetes.io/pod-name: prom-agent-{{ include "kube-prometheus-stack.prometheus.crname" $ }}-{{ $i }} + {{- else }} + app.kubernetes.io/name: prometheus + statefulset.kubernetes.io/pod-name: prometheus-{{ include "kube-prometheus-stack.prometheus.crname" $ }}-{{ $i }} + {{- end }} + operator.prometheus.io/name: {{ template "kube-prometheus-stack.prometheus.crname" $ }} + type: "{{ $serviceValues.type }}" +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/clusterrole.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/clusterrole.yaml new file mode 100644 index 0000000000..56ca9f5eae --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/clusterrole.yaml @@ -0,0 +1,135 @@ +{{- if and .Values.global.rbac.create .Values.global.rbac.userRoles.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: monitoring-admin + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} + {{- if .Values.global.rbac.userRoles.aggregateToDefaultRoles }} + rbac.authorization.k8s.io/aggregate-to-admin: "true" + {{- end }} +rules: +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - prometheuses/finalizers + - alertmanagers/finalizers + verbs: + - 'get' + - 'list' + - 'watch' +- apiGroups: + - monitoring.coreos.com + resources: + - thanosrulers + - thanosrulers/finalizers + - servicemonitors + - podmonitors + - prometheusrules + - podmonitors + - probes + - probes/finalizers + - alertmanagerconfigs + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: monitoring-edit + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} + {{- if .Values.global.rbac.userRoles.aggregateToDefaultRoles }} + rbac.authorization.k8s.io/aggregate-to-edit: "true" + {{- end }} +rules: +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - prometheuses/finalizers + - alertmanagers/finalizers + verbs: + - 'get' + - 'list' + - 'watch' +- apiGroups: + - monitoring.coreos.com + resources: + - thanosrulers + - thanosrulers/finalizers + - servicemonitors + - podmonitors + - prometheusrules + - podmonitors + - probes + - alertmanagerconfigs + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: monitoring-view + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} + {{- if .Values.global.rbac.userRoles.aggregateToDefaultRoles }} + rbac.authorization.k8s.io/aggregate-to-view: "true" + {{- end }} +rules: +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - prometheuses/finalizers + - alertmanagers/finalizers + - thanosrulers + - thanosrulers/finalizers + - servicemonitors + - podmonitors + - prometheusrules + - podmonitors + - probes + - probes/finalizers + - alertmanagerconfigs + verbs: + - 'get' + - 'list' + - 'watch' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: monitoring-ui-view + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - services/proxy + resourceNames: + - "http:{{ template "kube-prometheus-stack.fullname" . }}-prometheus:{{ .Values.prometheus.service.port }}" + - "https:{{ template "kube-prometheus-stack.fullname" . }}-prometheus:{{ .Values.prometheus.service.port }}" + - "http:{{ template "kube-prometheus-stack.fullname" . }}-alertmanager:{{ .Values.alertmanager.service.port }}" + - "https:{{ template "kube-prometheus-stack.fullname" . }}-alertmanager:{{ .Values.alertmanager.service.port }}" +{{- if .Values.grafana.enabled }} + - "http:{{ include "call-nested" (list . "grafana" "grafana.fullname") }}:{{ .Values.grafana.service.port }}" + - "https:{{ include "call-nested" (list . "grafana" "grafana.fullname") }}:{{ .Values.grafana.service.port }}" +{{- end }} + verbs: + - 'get' + - 'create' +- apiGroups: + - "" + resourceNames: + - {{ template "kube-prometheus-stack.fullname" . }}-prometheus + - {{ template "kube-prometheus-stack.fullname" . }}-alertmanager +{{- if .Values.grafana.enabled }} + - {{ include "call-nested" (list . "grafana" "grafana.fullname") }} +{{- end }} + resources: + - endpoints + verbs: + - list +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/config-role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/config-role.yaml new file mode 100644 index 0000000000..f48ffc827e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/config-role.yaml @@ -0,0 +1,48 @@ +{{- if and .Values.global.rbac.create .Values.global.rbac.userRoles.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: monitoring-config-admin + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: monitoring-config-edit + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: monitoring-config-view + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + - secrets + verbs: + - 'get' + - 'list' + - 'watch' +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboard-role.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboard-role.yaml new file mode 100644 index 0000000000..d2f81976a2 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboard-role.yaml @@ -0,0 +1,47 @@ +{{- if and .Values.global.rbac.create .Values.global.rbac.userRoles.create .Values.grafana.enabled }} +{{- if .Values.grafana.defaultDashboardsEnabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: monitoring-dashboard-admin + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: monitoring-dashboard-edit + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: monitoring-dashboard-view + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - 'get' + - 'list' + - 'watch' +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/addons/ingress-nginx-dashboard.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/addons/ingress-nginx-dashboard.yaml new file mode 100644 index 0000000000..7b51a0bf7a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/addons/ingress-nginx-dashboard.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled .Values.ingressNginx.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: {{ printf "%s-%s" (include "kube-prometheus-stack.fullname" $) "ingress-nginx" | trunc 63 | trimSuffix "-" }} + {{- if .Values.grafana.sidecar.dashboards.annotations }} + annotations: {{ toYaml .Values.grafana.sidecar.dashboards.annotations | nindent 4 }} + {{- end }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/ingress-nginx/*").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/cluster-dashboards.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/cluster-dashboards.yaml new file mode 100644 index 0000000000..d73b257451 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/cluster-dashboards.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-default-dashboards-cluster + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/cluster/*").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/default-dashboard.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/default-dashboard.yaml new file mode 100644 index 0000000000..8865efa932 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/default-dashboard.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-default-dashboards-home + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/home/*").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fleet-dashboards.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fleet-dashboards.yaml new file mode 100644 index 0000000000..9b05cea2e8 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fleet-dashboards.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-fleet-dashboards + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/fleet/*").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fluentbit-dashboard.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fluentbit-dashboard.yaml new file mode 100644 index 0000000000..b2d1bfcb73 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fluentbit-dashboard.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled .Values.loggingMonitors.fluentbit.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-fluentbit-dashboard + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/logging/fluentbit.json").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fluentd-dashboard.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fluentd-dashboard.yaml new file mode 100644 index 0000000000..66c9cb845a --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/fluentd-dashboard.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled .Values.loggingMonitors.fluentd.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-fluentd-dashboard + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/logging/fluentd.json").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/k8s-dashboards.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/k8s-dashboards.yaml new file mode 100644 index 0000000000..2afae10ef7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/k8s-dashboards.yaml @@ -0,0 +1,31 @@ +{{- $files := (.Files.Glob "files/rancher/k8s/*").AsConfig }} +{{- $filesDict := (fromYaml $files) }} +{{- if not (include "exporter.kubeEtcd.enabled" .) }} +{{- $filesDict = (unset $filesDict "rancher-etcd-nodes.json") -}} +{{- $filesDict = (unset $filesDict "rancher-etcd.json") -}} +{{- end }} +{{- if not (include "exporter.kubeControllerManager.enabled" .) }} +{{- $filesDict = (unset $filesDict "rancher-k8s-components-nodes.json") -}} +{{- $filesDict = (unset $filesDict "rancher-k8s-components.json") -}} +{{- else }} +{{- $_ := (set $filesDict "rancher-k8s-components-nodes.json" (get $filesDict "rancher-k8s-components-nodes.json" | replace "kube-controller-manager" (include "exporter.kubeControllerManager.jobName" .))) -}} +{{- $_ := (set $filesDict "rancher-k8s-components.json" (get $filesDict "rancher-k8s-components.json" | replace "kube-controller-manager" (include "exporter.kubeControllerManager.jobName" .))) -}} +{{- end }} +{{ $files = (toYaml $filesDict) }} +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-default-dashboards-k8s + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ $files | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/nodes-dashboards.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/nodes-dashboards.yaml new file mode 100644 index 0000000000..172c36e9d1 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/nodes-dashboards.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-default-dashboards-nodes + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/nodes/*").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/performance-dashboards.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/performance-dashboards.yaml new file mode 100644 index 0000000000..19836ec4e4 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/performance-dashboards.yaml @@ -0,0 +1,18 @@ +{{- $selector := (include "rancher.serviceMonitor.selector" .) -}} +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled .Values.rancherMonitoring.enabled $selector }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-default-dashboards-performance-debugging + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/performance/*").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/pods-dashboards.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/pods-dashboards.yaml new file mode 100644 index 0000000000..940f18869b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/pods-dashboards.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-default-dashboards-pods + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/pods/*").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/workload-dashboards.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/workload-dashboards.yaml new file mode 100644 index 0000000000..d146dacdd0 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/dashboards/rancher/workload-dashboards.yaml @@ -0,0 +1,17 @@ +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ .Values.grafana.defaultDashboards.namespace }} + name: rancher-default-dashboards-workloads + annotations: +{{ toYaml .Values.grafana.sidecar.dashboards.annotations | indent 4 }} + labels: + {{- if $.Values.grafana.sidecar.dashboards.label }} + {{ $.Values.grafana.sidecar.dashboards.label }}: "1" + {{- end }} + app: {{ template "kube-prometheus-stack.name" $ }}-grafana +{{ include "kube-prometheus-stack.labels" $ | indent 4 }} +data: +{{ (.Files.Glob "files/rancher/workloads/*").AsConfig | indent 2 }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/fleet/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/fleet/servicemonitor.yaml new file mode 100644 index 0000000000..90d24c2061 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/fleet/servicemonitor.yaml @@ -0,0 +1,53 @@ +{{- if .Values.rancherMonitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} + name: monitoring-fleet-controller + namespace: cattle-fleet-system +spec: + endpoints: + - port: metrics + metricRelabelings: + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} + jobLabel: fleet + selector: + matchLabels: + app: fleet-controller +{{- end }} +--- +{{- if .Values.rancherMonitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} + name: monitoring-gitops-controller + namespace: cattle-fleet-system +spec: + endpoints: + - port: metrics + metricRelabelings: + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} + jobLabel: gitops + selector: + matchLabels: + app: gitjob +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/network-policy.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/network-policy.yaml new file mode 100644 index 0000000000..07d3c03de4 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/network-policy.yaml @@ -0,0 +1,19 @@ +{{- if .Values.rke2IngressNginx.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + annotations: + np.rke2.io/ingress: resolved + name: rke2-ingress-network-policy + namespace: {{ include "rke2-ingress-nginx.namespace" . }} +spec: + ingress: + - ports: + - port: {{ .Values.rke2IngressNginx.metricsPort }} + protocol: TCP + podSelector: + matchLabels: + app.kubernetes.io/name: rke2-ingress-nginx + policyTypes: + - Ingress + {{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/service.yaml new file mode 100644 index 0000000000..53a9ad6897 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/service.yaml @@ -0,0 +1,27 @@ +{{- if and (not .Values.ingressNginx.enabled) (.Values.rkeIngressNginx.enabled) }} +{{- fail "Cannot set .Values.rkeIngressNginx.enabled=true when .Values.ingressNginx.enabled=false" }} +{{- end }} +{{- if and .Values.ingressNginx.enabled (not .Values.rkeIngressNginx.enabled) }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-ingress-nginx + labels: + app: {{ template "kube-prometheus-stack.name" . }}-ingress-nginx + jobLabel: ingress-nginx +{{ include "kube-prometheus-stack.labels" . | indent 4 }} + namespace: {{ .Values.ingressNginx.namespace }} +spec: + clusterIP: None + ports: + - name: http-metrics + port: {{ .Values.ingressNginx.service.port }} + protocol: TCP + targetPort: {{ .Values.ingressNginx.service.targetPort }} + selector: + {{- if .Values.ingressNginx.service.selector }} +{{ toYaml .Values.ingressNginx.service.selector | indent 4 }} + {{- else }} + app: ingress-nginx + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/servicemonitor.yaml new file mode 100644 index 0000000000..b0f92e63b5 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/ingress-nginx/servicemonitor.yaml @@ -0,0 +1,49 @@ +{{- if and (not .Values.ingressNginx.enabled) (.Values.rkeIngressNginx.enabled) }} +{{- fail "Cannot set .Values.rkeIngressNginx.enabled=true when .Values.ingressNginx.enabled=false" }} +{{- end }} +{{- if and .Values.ingressNginx.enabled (not .Values.rkeIngressNginx.enabled) }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-ingress-nginx + namespace: {{ .Values.ingressNginx.namespace }} + labels: + app: {{ template "kube-prometheus-stack.name" . }}-ingress-nginx +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + jobLabel: jobLabel + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.name" . }}-ingress-nginx + release: {{ $.Release.Name | quote }} + namespaceSelector: + matchNames: + - {{ .Values.ingressNginx.namespace }} + endpoints: + - port: http-metrics + {{- if .Values.ingressNginx.serviceMonitor.interval}} + interval: {{ .Values.ingressNginx.serviceMonitor.interval }} + {{- end }} + {{- if .Values.ingressNginx.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.ingressNginx.serviceMonitor.proxyUrl}} + {{- end }} + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + metricRelabelings: + {{- if .Values.ingressNginx.serviceMonitor.metricRelabelings }} + {{ tpl (toYaml .Values.ingressNginx.serviceMonitor.metricRelabelings | indent 4) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} +{{- if .Values.ingressNginx.serviceMonitor.relabelings }} + relabelings: +{{ toYaml .Values.ingressNginx.serviceMonitor.relabelings | indent 4 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/rancher/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/rancher/servicemonitor.yaml new file mode 100644 index 0000000000..1fba8f23f7 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/exporters/rancher/servicemonitor.yaml @@ -0,0 +1,58 @@ +{{- $selector := (include "rancher.serviceMonitor.selector" .) -}} +{{- if and .Values.rancherMonitoring.enabled $selector }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + labels: {{ include "kube-prometheus-stack.labels" . | nindent 4 }} + name: rancher + namespace: cattle-system +spec: + endpoints: + - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token + port: http + tlsConfig: + caFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecureSkipVerify: true + serverName: rancher + metricRelabelings: + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} + jobLabel: rancher +{{- if .Values.rancherMonitoring.namespaceSelector }} + namespaceSelector: {{ .Values.rancherMonitoring.namespaceSelector | toYaml | nindent 4 }} +{{- end }} + selector: {{ include "rancher.serviceMonitor.selector" . | nindent 4 }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-rancher-metrics +rules: +- apiGroups: + - management.cattle.io + resources: + - ranchermetrics + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-rancher-metrics +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "kube-prometheus-stack.fullname" . }}-rancher-metrics +subjects: + - kind: ServiceAccount + name: {{ template "kube-prometheus-stack.fullname" . }}-prometheus + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/hardened.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/hardened.yaml new file mode 100644 index 0000000000..63bac7fd42 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/hardened.yaml @@ -0,0 +1,91 @@ +{{- $namespaces := dict "_0" .Release.Namespace -}} +{{- if and .Values.grafana.enabled .Values.grafana.defaultDashboardsEnabled (not .Values.grafana.defaultDashboards.useExistingNamespace) -}} +{{- $_ := set $namespaces "_1" .Values.grafana.defaultDashboards.namespace -}} +{{- end -}} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Chart.Name }}-patch-sa + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Chart.Name }}-patch-sa + annotations: + "helm.sh/hook": post-install, post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded, before-hook-creation +spec: + template: + metadata: + name: {{ .Chart.Name }}-patch-sa + labels: + app: {{ .Chart.Name }}-patch-sa + spec: + serviceAccountName: {{ .Chart.Name }}-patch-sa + securityContext: + runAsNonRoot: true + runAsUser: 1000 + restartPolicy: Never + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} + containers: + {{- range $_, $ns := $namespaces }} + - name: patch-sa-{{ $ns }} + image: {{ template "system_default_registry" $ }}{{ $.Values.global.kubectl.repository }}:{{ $.Values.global.kubectl.tag }} + imagePullPolicy: {{ $.Values.global.kubectl.pullPolicy }} + command: ["kubectl", "patch", "serviceaccount", "default", "-p", "{\"automountServiceAccountToken\": false}"] + args: ["-n", "{{ $ns }}"] + {{- end }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ .Chart.Name }}-patch-sa + labels: + app: {{ .Chart.Name }}-patch-sa +rules: +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: ['get', 'patch'] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Chart.Name }}-patch-sa + labels: + app: {{ .Chart.Name }}-patch-sa +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Chart.Name }}-patch-sa +subjects: +- kind: ServiceAccount + name: {{ .Chart.Name }}-patch-sa + namespace: {{ .Release.Namespace }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Chart.Name }}-patch-sa + namespace: {{ .Release.Namespace }} + labels: + app: {{ .Chart.Name }}-patch-sa +--- +{{- if .Values.hardened.k3s.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: rancher-monitoring-coredns-allow-all + namespace: kube-system +spec: + ingress: + - {} + egress: + - {} + policyTypes: + - Ingress + - Egress + podSelector: + matchLabels: + k8s-app: kube-dns +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/configmap.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/configmap.yaml new file mode 100644 index 0000000000..53cb898214 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/configmap.yaml @@ -0,0 +1,13 @@ +{{- if .Values.upgrade.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + namespace: {{ template "kube-prometheus-stack.namespace" . }} + annotations: + "helm.sh/hook": pre-upgrade, pre-rollback + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed + "helm.sh/hook-weight": "0" +data: +{{ (.Files.Glob "files/upgrade/scripts/*").AsConfig | indent 2 }} +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/job.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/job.yaml new file mode 100644 index 0000000000..8f2771740c --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/job.yaml @@ -0,0 +1,46 @@ +{{- if .Values.upgrade.enabled }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + annotations: + "helm.sh/hook": pre-upgrade, pre-rollback + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed + "helm.sh/hook-weight": "2" +spec: + template: + metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + labels: + app: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + spec: + serviceAccountName: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + securityContext: + runAsNonRoot: false + runAsUser: 0 + restartPolicy: Never + nodeSelector: {{ include "linux-node-selector" . | nindent 8 }} + tolerations: {{ include "linux-node-tolerations" . | nindent 8 }} + containers: + - name: run-scripts + image: {{ template "system_default_registry" . }}{{ .Values.upgrade.image.repository }}:{{ .Values.upgrade.image.tag }} + imagePullPolicy: {{ $.Values.global.kubectl.pullPolicy }} + command: + - /bin/sh + - -c + - > + for s in $(find /etc/scripts -type f); do + echo "Running $s..."; + cat $s | bash + done; + volumeMounts: + - name: upgrade + mountPath: /etc/scripts + volumes: + - name: upgrade + configMap: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/rbac.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/rbac.yaml new file mode 100644 index 0000000000..46bdd3a36b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/rancher-monitoring/upgrade/rbac.yaml @@ -0,0 +1,86 @@ +{{- if .Values.upgrade.enabled }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + annotations: + "helm.sh/hook": pre-upgrade, pre-rollback + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded + "helm.sh/hook-weight": "1" +rules: +- apiGroups: + - apps + resources: + - deployments + - daemonsets + - statefulsets + verbs: + - 'list' + - 'delete' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + annotations: + "helm.sh/hook": pre-upgrade, pre-rollback + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed + "helm.sh/hook-weight": "1" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade +subjects: +- kind: ServiceAccount + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + namespace: {{ template "kube-prometheus-stack.namespace" . }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + labels: + app: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + annotations: + "helm.sh/hook": pre-upgrade, pre-rollback + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed + "helm.sh/hook-weight": "1" +rules: +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + labels: + app: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + annotations: + "helm.sh/hook": pre-upgrade, pre-rollback + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed + "helm.sh/hook-weight": "1" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade +subjects: +- kind: ServiceAccount + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + namespace: {{ template "kube-prometheus-stack.namespace" . }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.fullname" . }}-upgrade + annotations: + "helm.sh/hook": pre-upgrade, pre-rollback + "helm.sh/hook-delete-policy": before-hook-creation, hook-succeeded, hook-failed + "helm.sh/hook-weight": "1" +{{- end }} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/extrasecret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/extrasecret.yaml new file mode 100644 index 0000000000..587fca2dca --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/extrasecret.yaml @@ -0,0 +1,20 @@ +{{- if .Values.thanosRuler.extraSecret.data -}} +{{- $secretName := printf "%s-extra" (include "kube-prometheus-stack.thanosRuler.name" . ) -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default $secretName .Values.thanosRuler.extraSecret.name }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- if .Values.thanosRuler.extraSecret.annotations }} + annotations: +{{ toYaml .Values.thanosRuler.extraSecret.annotations | indent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + app.kubernetes.io/component: thanos-ruler +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: +{{- range $key, $val := .Values.thanosRuler.extraSecret.data }} + {{ $key }}: {{ $val | b64enc | quote }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/ingress.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/ingress.yaml new file mode 100644 index 0000000000..e245ad448e --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/ingress.yaml @@ -0,0 +1,77 @@ +{{- if and .Values.thanosRuler.enabled .Values.thanosRuler.ingress.enabled }} +{{- $pathType := .Values.thanosRuler.ingress.pathType | default "ImplementationSpecific" }} +{{- $serviceName := include "kube-prometheus-stack.thanosRuler.name" . }} +{{- $servicePort := .Values.thanosRuler.service.port -}} +{{- $routePrefix := list .Values.thanosRuler.thanosRulerSpec.routePrefix }} +{{- $paths := .Values.thanosRuler.ingress.paths | default $routePrefix -}} +{{- $apiIsStable := eq (include "kube-prometheus-stack.ingress.isStable" .) "true" -}} +{{- $ingressSupportsPathType := eq (include "kube-prometheus-stack.ingress.supportsPathType" .) "true" -}} +apiVersion: {{ include "kube-prometheus-stack.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ $serviceName }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} +{{- if .Values.thanosRuler.ingress.annotations }} + annotations: + {{- tpl (toYaml .Values.thanosRuler.ingress.annotations) . | nindent 4 }} +{{- end }} + labels: + app: {{ template "kube-prometheus-stack.thanosRuler.name" . }} +{{- if .Values.thanosRuler.ingress.labels }} +{{ toYaml .Values.thanosRuler.ingress.labels | indent 4 }} +{{- end }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + {{- if $apiIsStable }} + {{- if .Values.thanosRuler.ingress.ingressClassName }} + ingressClassName: {{ .Values.thanosRuler.ingress.ingressClassName }} + {{- end }} + {{- end }} + rules: + {{- if .Values.thanosRuler.ingress.hosts }} + {{- range $host := .Values.thanosRuler.ingress.hosts }} + - host: {{ tpl $host $ }} + http: + paths: + {{- range $p := $paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end -}} + {{- end -}} + {{- else }} + - http: + paths: + {{- range $p := $paths }} + - path: {{ tpl $p $ }} + {{- if and $pathType $ingressSupportsPathType }} + pathType: {{ $pathType }} + {{- end }} + backend: + {{- if $apiIsStable }} + service: + name: {{ $serviceName }} + port: + number: {{ $servicePort }} + {{- else }} + serviceName: {{ $serviceName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- end -}} + {{- end -}} + {{- if .Values.thanosRuler.ingress.tls }} + tls: +{{ tpl (toYaml .Values.thanosRuler.ingress.tls | indent 4) . }} + {{- end -}} +{{- end -}} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/podDisruptionBudget.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/podDisruptionBudget.yaml new file mode 100644 index 0000000000..c28f914647 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/podDisruptionBudget.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.thanosRuler.enabled .Values.thanosRuler.podDisruptionBudget.enabled }} +apiVersion: {{ include "kube-prometheus-stack.pdb.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.thanosRuler.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +spec: + {{- if .Values.thanosRuler.podDisruptionBudget.minAvailable }} + minAvailable: {{ .Values.thanosRuler.podDisruptionBudget.minAvailable }} + {{- end }} + {{- if .Values.thanosRuler.podDisruptionBudget.maxUnavailable }} + maxUnavailable: {{ .Values.thanosRuler.podDisruptionBudget.maxUnavailable }} + {{- end }} + selector: + matchLabels: + app.kubernetes.io/name: thanos-ruler + thanos-ruler: {{ template "kube-prometheus-stack.thanosRuler.crname" . }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/ruler.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/ruler.yaml new file mode 100644 index 0000000000..94dc60be3f --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/ruler.yaml @@ -0,0 +1,200 @@ +{{- if .Values.thanosRuler.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ThanosRuler +metadata: + name: {{ template "kube-prometheus-stack.thanosRuler.crname" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ include "kube-prometheus-stack.thanosRuler.name" . }} +{{- include "kube-prometheus-stack.labels" . | indent 4 -}} +{{- if .Values.thanosRuler.annotations }} + annotations: +{{ toYaml .Values.thanosRuler.annotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.thanosRuler.thanosRulerSpec.image }} + {{- $registry := include "monitoring_registry" . | default .Values.thanosRuler.thanosRulerSpec.image.registry -}} + {{- if and .Values.thanosRuler.thanosRulerSpec.image.tag .Values.thanosRuler.thanosRulerSpec.image.sha }} + image: "{{ $registry }}/{{ .Values.thanosRuler.thanosRulerSpec.image.repository }}:{{ .Values.thanosRuler.thanosRulerSpec.image.tag }}@sha256:{{ .Values.thanosRuler.thanosRulerSpec.image.sha }}" + {{- else if .Values.thanosRuler.thanosRulerSpec.image.sha }} + image: "{{ $registry }}/{{ .Values.thanosRuler.thanosRulerSpec.image.repository }}@sha256:{{ .Values.thanosRuler.thanosRulerSpec.image.sha }}" + {{- else if .Values.thanosRuler.thanosRulerSpec.image.tag }} + image: "{{ $registry }}/{{ .Values.thanosRuler.thanosRulerSpec.image.repository }}:{{ .Values.thanosRuler.thanosRulerSpec.image.tag }}" + {{- else }} + image: "{{ $registry }}/{{ .Values.thanosRuler.thanosRulerSpec.image.repository }}" + {{- end }} + {{- if .Values.thanosRuler.thanosRulerSpec.image.sha }} + sha: {{ .Values.thanosRuler.thanosRulerSpec.image.sha }} + {{- end }} +{{- end }} + replicas: {{ .Values.thanosRuler.thanosRulerSpec.replicas }} + listenLocal: {{ .Values.thanosRuler.thanosRulerSpec.listenLocal }} + serviceAccountName: {{ template "kube-prometheus-stack.thanosRuler.serviceAccountName" . }} +{{- if .Values.thanosRuler.thanosRulerSpec.externalPrefix }} + externalPrefix: "{{ tpl .Values.thanosRuler.thanosRulerSpec.externalPrefix . }}" +{{- else if and .Values.thanosRuler.ingress.enabled .Values.thanosRuler.ingress.hosts }} + externalPrefix: "http://{{ tpl (index .Values.thanosRuler.ingress.hosts 0) . }}{{ .Values.thanosRuler.thanosRulerSpec.routePrefix }}" +{{- else if .Values.thanosRuler.thanosRulerSpec.externalPrefixNilUsesHelmValues }} + externalPrefix: "http://{{ template "kube-prometheus-stack.thanosRuler.name" . }}.{{ template "kube-prometheus-stack.namespace" . }}:{{ .Values.thanosRuler.service.port }}" +{{- end }} + nodeSelector: {{ include "linux-node-selector" . | nindent 4 }} +{{- if .Values.thanosRuler.thanosRulerSpec.additionalArgs }} + additionalArgs: +{{ tpl (toYaml .Values.thanosRuler.thanosRulerSpec.additionalArgs) $ | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.nodeSelector }} + nodeSelector: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.nodeSelector | indent 4 }} +{{- end }} + paused: {{ .Values.thanosRuler.thanosRulerSpec.paused }} + logFormat: {{ .Values.thanosRuler.thanosRulerSpec.logFormat | quote }} + logLevel: {{ .Values.thanosRuler.thanosRulerSpec.logLevel | quote }} + retention: {{ .Values.thanosRuler.thanosRulerSpec.retention | quote }} +{{- if .Values.thanosRuler.thanosRulerSpec.evaluationInterval }} + evaluationInterval: {{ .Values.thanosRuler.thanosRulerSpec.evaluationInterval }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.ruleNamespaceSelector }} + ruleNamespaceSelector: +{{ tpl (toYaml .Values.thanosRuler.thanosRulerSpec.ruleNamespaceSelector | indent 4) . }} +{{ else }} + ruleNamespaceSelector: {} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.ruleSelector }} + ruleSelector: +{{ tpl (toYaml .Values.thanosRuler.thanosRulerSpec.ruleSelector | indent 4) .}} +{{- else if .Values.thanosRuler.thanosRulerSpec.ruleSelectorNilUsesHelmValues }} + ruleSelector: + matchLabels: + release: {{ $.Release.Name | quote }} +{{ else }} + ruleSelector: {} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.alertQueryUrl }} + alertQueryUrl: "{{ .Values.thanosRuler.thanosRulerSpec.alertQueryUrl }}" +{{- end}} +{{- if .Values.thanosRuler.thanosRulerSpec.alertmanagersUrl }} + alertmanagersUrl: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.alertmanagersUrl | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.alertmanagersConfig.existingSecret }} + alertmanagersConfig: + key: "{{.Values.thanosRuler.thanosRulerSpec.alertmanagersConfig.existingSecret.key }}" + name: "{{.Values.thanosRuler.thanosRulerSpec.alertmanagersConfig.existingSecret.name }}" +{{- else if .Values.thanosRuler.thanosRulerSpec.alertmanagersConfig.secret }} + alertmanagersConfig: + key: alertmanager-configs.yaml + name: {{ template "kube-prometheus-stack.thanosRuler.name" . }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.queryEndpoints }} + queryEndpoints: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.queryEndpoints | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.queryConfig.existingSecret }} + queryConfig: + key: "{{.Values.thanosRuler.thanosRulerSpec.queryConfig.existingSecret.key }}" + name: "{{.Values.thanosRuler.thanosRulerSpec.queryConfig.existingSecret.name }}" +{{- else if .Values.thanosRuler.thanosRulerSpec.queryConfig.secret }} + queryConfig: + key: query-configs.yaml + name: {{ template "kube-prometheus-stack.thanosRuler.name" . }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.resources }} + resources: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.resources | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.routePrefix }} + routePrefix: "{{ .Values.thanosRuler.thanosRulerSpec.routePrefix }}" +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.securityContext }} + securityContext: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.securityContext | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.storage }} + storage: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.storage | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.objectStorageConfig.existingSecret }} + objectStorageConfig: + key: "{{.Values.thanosRuler.thanosRulerSpec.objectStorageConfig.existingSecret.key }}" + name: "{{.Values.thanosRuler.thanosRulerSpec.objectStorageConfig.existingSecret.name }}" +{{- else if .Values.thanosRuler.thanosRulerSpec.objectStorageConfig.secret }} + objectStorageConfig: + key: object-storage-configs.yaml + name: {{ template "kube-prometheus-stack.thanosRuler.name" . }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.labels }} + labels: +{{ tpl (toYaml .Values.thanosRuler.thanosRulerSpec.labels) $ | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.podMetadata }} + podMetadata: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.podMetadata | indent 4 }} +{{- end }} +{{- if or .Values.thanosRuler.thanosRulerSpec.podAntiAffinity .Values.thanosRuler.thanosRulerSpec.affinity }} + affinity: +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.affinity }} +{{ toYaml .Values.thanosRuler.thanosRulerSpec.affinity | indent 4 }} +{{- end }} +{{- if eq .Values.thanosRuler.thanosRulerSpec.podAntiAffinity "hard" }} + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: {{ .Values.thanosRuler.thanosRulerSpec.podAntiAffinityTopologyKey }} + labelSelector: + matchExpressions: + - {key: app.kubernetes.io/name, operator: In, values: [thanos-ruler]} + - {key: thanos-ruler, operator: In, values: [{{ template "kube-prometheus-stack.thanosRuler.crname" . }}]} +{{- else if eq .Values.thanosRuler.thanosRulerSpec.podAntiAffinity "soft" }} + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: {{ .Values.thanosRuler.thanosRulerSpec.podAntiAffinityTopologyKey }} + labelSelector: + matchExpressions: + - {key: app.kubernetes.io/name, operator: In, values: [thanos-ruler]} + - {key: thanos-ruler, operator: In, values: [{{ template "kube-prometheus-stack.thanosRuler.crname" . }}]} +{{- end }} + tolerations: {{ include "linux-node-tolerations" . | nindent 4 }} +{{- if .Values.thanosRuler.thanosRulerSpec.tolerations }} +{{ toYaml .Values.thanosRuler.thanosRulerSpec.tolerations | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.topologySpreadConstraints | indent 4 }} +{{- end }} +{{- if .Values.global.imagePullSecrets }} + imagePullSecrets: +{{ toYaml .Values.global.imagePullSecrets | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.containers }} + containers: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.containers | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.initContainers }} + initContainers: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.initContainers | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.priorityClassName }} + priorityClassName: {{.Values.thanosRuler.thanosRulerSpec.priorityClassName }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.volumes }} + volumes: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.volumes | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.volumeMounts }} + volumeMounts: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.volumeMounts | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.thanosRulerSpec.alertDropLabels }} + alertDropLabels: +{{ toYaml .Values.thanosRuler.thanosRulerSpec.alertDropLabels | indent 4 }} +{{- end }} + portName: {{ .Values.thanosRuler.thanosRulerSpec.portName }} +{{- with .Values.thanosRuler.thanosRulerSpec.additionalConfig }} + {{- tpl (toYaml .) $ | nindent 2 }} +{{- end }} +{{- with .Values.thanosRuler.thanosRulerSpec.additionalConfigString }} + {{- tpl . $ | nindent 2 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/secret.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/secret.yaml new file mode 100644 index 0000000000..acab7fd9ae --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/secret.yaml @@ -0,0 +1,26 @@ +{{- if .Values.thanosRuler.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ include "kube-prometheus-stack.thanosRuler.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +data: + {{- with .Values.thanosRuler.thanosRulerSpec.alertmanagersConfig }} + {{- if and .secret (not .existingSecret) }} + alertmanager-configs.yaml: {{ toYaml .secret | b64enc | quote }} + {{- end }} + {{- end }} + {{- with .Values.thanosRuler.thanosRulerSpec.objectStorageConfig }} + {{- if and .secret (not .existingSecret) }} + object-storage-configs.yaml: {{ toYaml .secret | b64enc | quote }} + {{- end }} + {{- end }} + {{- with .Values.thanosRuler.thanosRulerSpec.queryConfig }} + {{- if and .secret (not .existingSecret) }} + query-configs.yaml: {{ toYaml .secret | b64enc | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/service.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/service.yaml new file mode 100644 index 0000000000..e2cca29188 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/service.yaml @@ -0,0 +1,57 @@ +{{- if .Values.thanosRuler.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + self-monitor: {{ .Values.thanosRuler.serviceMonitor.selfMonitor | quote }} +{{- include "kube-prometheus-stack.labels" . | indent 4 -}} +{{- if .Values.thanosRuler.service.labels }} +{{ toYaml .Values.thanosRuler.service.labels | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.service.annotations }} + annotations: +{{ toYaml .Values.thanosRuler.service.annotations | indent 4 }} +{{- end }} +spec: +{{- if .Values.thanosRuler.service.clusterIP }} + clusterIP: {{ .Values.thanosRuler.service.clusterIP }} +{{- end }} +{{- if .Values.thanosRuler.service.ipDualStack.enabled }} + ipFamilies: {{ toYaml .Values.thanosRuler.service.ipDualStack.ipFamilies | nindent 4 }} + ipFamilyPolicy: {{ .Values.thanosRuler.service.ipDualStack.ipFamilyPolicy }} +{{- end }} +{{- if .Values.thanosRuler.service.externalIPs }} + externalIPs: +{{ toYaml .Values.thanosRuler.service.externalIPs | indent 4 }} +{{- end }} +{{- if .Values.thanosRuler.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.thanosRuler.service.loadBalancerIP }} +{{- end }} +{{- if .Values.thanosRuler.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: + {{- range $cidr := .Values.thanosRuler.service.loadBalancerSourceRanges }} + - {{ $cidr }} + {{- end }} +{{- end }} +{{- if ne .Values.thanosRuler.service.type "ClusterIP" }} + externalTrafficPolicy: {{ .Values.thanosRuler.service.externalTrafficPolicy }} +{{- end }} + ports: + - name: {{ .Values.thanosRuler.thanosRulerSpec.portName }} + {{- if eq .Values.thanosRuler.service.type "NodePort" }} + nodePort: {{ .Values.thanosRuler.service.nodePort }} + {{- end }} + port: {{ .Values.thanosRuler.service.port }} + targetPort: {{ .Values.thanosRuler.service.targetPort }} + protocol: TCP +{{- if .Values.thanosRuler.service.additionalPorts }} +{{ toYaml .Values.thanosRuler.service.additionalPorts | indent 2 }} +{{- end }} + selector: + app.kubernetes.io/name: thanos-ruler + thanos-ruler: {{ template "kube-prometheus-stack.thanosRuler.crname" . }} + type: "{{ .Values.thanosRuler.service.type }}" +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/serviceaccount.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/serviceaccount.yaml new file mode 100644 index 0000000000..b58f1cd4df --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/serviceaccount.yaml @@ -0,0 +1,20 @@ +{{- if and .Values.thanosRuler.enabled .Values.thanosRuler.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "kube-prometheus-stack.thanosRuler.serviceAccountName" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + app.kubernetes.io/name: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + app.kubernetes.io/component: thanos-ruler +{{- include "kube-prometheus-stack.labels" . | indent 4 -}} +{{- if .Values.thanosRuler.serviceAccount.annotations }} + annotations: +{{ toYaml .Values.thanosRuler.serviceAccount.annotations | indent 4 }} +{{- end }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{ toYaml .Values.global.imagePullSecrets | indent 2 }} +{{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/servicemonitor.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/servicemonitor.yaml new file mode 100644 index 0000000000..d26ddce93b --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/thanos-ruler/servicemonitor.yaml @@ -0,0 +1,82 @@ +{{- if and .Values.thanosRuler.enabled .Values.thanosRuler.serviceMonitor.selfMonitor }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + namespace: {{ template "kube-prometheus-stack.namespace" . }} + labels: + app: {{ template "kube-prometheus-stack.thanosRuler.name" . }} +{{ include "kube-prometheus-stack.labels" . | indent 4 }} +{{- with .Values.thanosRuler.serviceMonitor.additionalLabels }} +{{- toYaml . | nindent 4 }} +{{- end }} +spec: + {{- include "servicemonitor.scrapeLimits" .Values.thanosRuler.serviceMonitor | nindent 2 }} + selector: + matchLabels: + app: {{ template "kube-prometheus-stack.thanosRuler.name" . }} + release: {{ $.Release.Name | quote }} + self-monitor: {{ .Values.thanosRuler.serviceMonitor.selfMonitor | quote }} + namespaceSelector: + matchNames: + - {{ printf "%s" (include "kube-prometheus-stack.namespace" .) | quote }} + endpoints: + - port: {{ .Values.thanosRuler.thanosRulerSpec.portName }} + {{- if .Values.thanosRuler.serviceMonitor.interval }} + interval: {{ .Values.thanosRuler.serviceMonitor.interval }} + {{- end }} + {{- if .Values.thanosRuler.serviceMonitor.proxyUrl }} + proxyUrl: {{ .Values.thanosRuler.serviceMonitor.proxyUrl}} + {{- end }} + {{- if .Values.thanosRuler.serviceMonitor.scheme }} + scheme: {{ .Values.thanosRuler.serviceMonitor.scheme }} + {{- end }} + {{- if .Values.thanosRuler.serviceMonitor.bearerTokenFile }} + bearerTokenFile: {{ .Values.thanosRuler.serviceMonitor.bearerTokenFile }} + {{- end }} + {{- if .Values.thanosRuler.serviceMonitor.tlsConfig }} + tlsConfig: {{- toYaml .Values.thanosRuler.serviceMonitor.tlsConfig | nindent 6 }} + {{- end }} + path: "{{ trimSuffix "/" .Values.thanosRuler.thanosRulerSpec.routePrefix }}/metrics" + {{- if .Values.thanosRuler.serviceMonitor.metricRelabelings }} + metricRelabelings: {{- tpl (toYaml .Values.thanosRuler.serviceMonitor.metricRelabelings | nindent 6) . }} + {{- end }} + {{ if .Values.global.cattle.clusterId }} + - sourceLabels: [__address__] + targetLabel: cluster_id + replacement: {{ .Values.global.cattle.clusterId }} + {{- end }} + {{ if .Values.global.cattle.clusterName}} + - sourceLabels: [__address__] + targetLabel: cluster_name + replacement: {{ .Values.global.cattle.clusterName }} + {{- end }} + {{- if .Values.thanosRuler.serviceMonitor.relabelings }} + relabelings: {{- toYaml .Values.thanosRuler.serviceMonitor.relabelings | nindent 6 }} + {{- end }} + {{- range .Values.thanosRuler.serviceMonitor.additionalEndpoints }} + - port: {{ .port }} + {{- if or $.Values.thanosRuler.serviceMonitor.interval .interval }} + interval: {{ default $.Values.thanosRuler.serviceMonitor.interval .interval }} + {{- end }} + {{- if or $.Values.thanosRuler.serviceMonitor.proxyUrl .proxyUrl }} + proxyUrl: {{ default $.Values.thanosRuler.serviceMonitor.proxyUrl .proxyUrl }} + {{- end }} + {{- if or $.Values.thanosRuler.serviceMonitor.scheme .scheme }} + scheme: {{ default $.Values.thanosRuler.serviceMonitor.scheme .scheme }} + {{- end }} + {{- if or $.Values.thanosRuler.serviceMonitor.bearerTokenFile .bearerTokenFile }} + bearerTokenFile: {{ default $.Values.thanosRuler.serviceMonitor.bearerTokenFile .bearerTokenFile }} + {{- end }} + {{- if or $.Values.thanosRuler.serviceMonitor.tlsConfig .tlsConfig }} + tlsConfig: {{- default $.Values.thanosRuler.serviceMonitor.tlsConfig .tlsConfig | toYaml | nindent 6 }} + {{- end }} + path: {{ .path }} + {{- if or $.Values.thanosRuler.serviceMonitor.metricRelabelings .metricRelabelings }} + metricRelabelings: {{- tpl (default $.Values.thanosRuler.serviceMonitor.metricRelabelings .metricRelabelings | toYaml | nindent 6) . }} + {{- end }} + {{- if or $.Values.thanosRuler.serviceMonitor.relabelings .relabelings }} + relabelings: {{- default $.Values.thanosRuler.serviceMonitor.relabelings .relabelings | toYaml | nindent 6 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/validate-install-crd.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/validate-install-crd.yaml new file mode 100644 index 0000000000..6fcb8b3a69 --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/validate-install-crd.yaml @@ -0,0 +1,23 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +# {{- $found := dict -}} +# {{- set $found "monitoring.coreos.com/v1alpha1/AlertmanagerConfig" false -}} +# {{- set $found "monitoring.coreos.com/v1/Alertmanager" false -}} +# {{- set $found "monitoring.coreos.com/v1/PodMonitor" false -}} +# {{- set $found "monitoring.coreos.com/v1/Probe" false -}} +# {{- set $found "monitoring.coreos.com/v1alpha1/PrometheusAgent" false -}} +# {{- set $found "monitoring.coreos.com/v1/Prometheus" false -}} +# {{- set $found "monitoring.coreos.com/v1/PrometheusRule" false -}} +# {{- set $found "monitoring.coreos.com/v1alpha1/ScrapeConfig" false -}} +# {{- set $found "monitoring.coreos.com/v1/ServiceMonitor" false -}} +# {{- set $found "monitoring.coreos.com/v1/ThanosRuler" false -}} +# {{- range .Capabilities.APIVersions -}} +# {{- if hasKey $found (toString .) -}} +# {{- set $found (toString .) true -}} +# {{- end -}} +# {{- end -}} +# {{- range $_, $exists := $found -}} +# {{- if (eq $exists false) -}} +# {{- required "Required CRDs are missing. Please install the corresponding CRD chart before installing this chart." "" -}} +# {{- end -}} +# {{- end -}} +#{{- end -}} \ No newline at end of file diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/templates/validate-psp-install.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/validate-psp-install.yaml new file mode 100644 index 0000000000..b115feb1af --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/templates/validate-psp-install.yaml @@ -0,0 +1,2 @@ +#{{- if gt (len (lookup "rbac.authorization.k8s.io/v1" "ClusterRole" "" "")) 0 -}} +#{{- end }} diff --git a/charts/rancher-monitoring/105.1.3+up61.3.2/values.yaml b/charts/rancher-monitoring/105.1.3+up61.3.2/values.yaml new file mode 100644 index 0000000000..11233883ab --- /dev/null +++ b/charts/rancher-monitoring/105.1.3+up61.3.2/values.yaml @@ -0,0 +1,5567 @@ +# Default values for kube-prometheus-stack. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Rancher Monitoring Configuration + +## Configuration for prometheus-adapter +## ref: https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-adapter +## +prometheus-adapter: + enabled: true + prometheus: + # Change this if you change the namespaceOverride or nameOverride of prometheus-operator + url: http://rancher-monitoring-prometheus.cattle-monitoring-system.svc + port: 9090 + +## RKE PushProx Monitoring +## ref: https://github.com/rancher/charts/tree/dev-v2.9/packages/rancher-monitoring/rancher-pushprox +## +rkeControllerManager: + enabled: false + metricsPort: 10257 # default to secure port as of k8s >= 1.22 + component: kube-controller-manager + clients: + https: + enabled: true + insecureSkipVerify: true + useServiceAccountCredentials: true + port: 10011 + useLocalhost: true + nodeSelector: + node-role.kubernetes.io/controlplane: "true" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + kubeVersionOverrides: + - constraint: "< 1.22" + values: + metricsPort: 10252 # default to insecure port in k8s < 1.22 + clients: + https: + enabled: false + insecureSkipVerify: false + useServiceAccountCredentials: false + +rkeScheduler: + enabled: false + metricsPort: 10259 + component: kube-scheduler + clients: + https: + enabled: true + insecureSkipVerify: true + useServiceAccountCredentials: true + port: 10012 + useLocalhost: true + nodeSelector: + node-role.kubernetes.io/controlplane: "true" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + kubeVersionOverrides: + - constraint: "< 1.23" + values: + metricsPort: 10251 # default to insecure port in k8s < 1.23 + clients: + https: + enabled: false + insecureSkipVerify: false + useServiceAccountCredentials: false + +rkeProxy: + enabled: false + metricsPort: 10249 + component: kube-proxy + clients: + port: 10013 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +rkeEtcd: + enabled: false + metricsPort: 2379 + component: kube-etcd + clients: + port: 10014 + https: + enabled: true + certDir: /etc/kubernetes/ssl + certFile: kube-etcd-*.pem + keyFile: kube-etcd-*-key.pem + caCertFile: kube-ca.pem + seLinuxOptions: + # Gives rkeEtcd permissions to read files in /etc/kubernetes/* + # Type is defined in https://github.com/rancher/rancher-selinux + type: rke_kubereader_t + nodeSelector: + node-role.kubernetes.io/etcd: "true" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +rkeIngressNginx: + enabled: false + metricsPort: 10254 + component: ingress-nginx + clients: + port: 10015 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + nodeSelector: + node-role.kubernetes.io/worker: "true" + +## k3s PushProx Monitoring +## ref: https://github.com/rancher/charts/tree/dev-v2.9/packages/rancher-monitoring/rancher-pushprox +## +k3sServer: + enabled: false + metricsPort: 10250 + component: k3s-server + clients: + port: 10013 + useLocalhost: true + https: + enabled: true + useServiceAccountCredentials: true + insecureSkipVerify: true + rbac: + additionalRules: + - nonResourceURLs: ["/metrics/cadvisor"] + verbs: ["get"] + - apiGroups: [""] + resources: ["nodes/metrics"] + verbs: ["get"] + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + serviceMonitor: + endpoints: + - port: metrics + honorLabels: true + relabelings: + - sourceLabels: [__metrics_path__] + targetLabel: metrics_path + - port: metrics + path: /metrics/cadvisor + honorLabels: true + relabelings: + - sourceLabels: [__metrics_path__] + targetLabel: metrics_path + - port: metrics + path: /metrics/probes + honorLabels: true + relabelings: + - sourceLabels: [__metrics_path__] + targetLabel: metrics_path + +hardened: + k3s: + networkPolicy: + enabled: true + +## KubeADM PushProx Monitoring +## ref: https://github.com/rancher/charts/tree/dev-v2.9/packages/rancher-monitoring/rancher-pushprox +## +kubeAdmControllerManager: + enabled: false + metricsPort: 10257 + component: kube-controller-manager + clients: + port: 10011 + useLocalhost: true + https: + enabled: true + useServiceAccountCredentials: true + insecureSkipVerify: true + nodeSelector: + node-role.kubernetes.io/master: "" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +kubeAdmScheduler: + enabled: false + metricsPort: 10259 + component: kube-scheduler + clients: + port: 10012 + useLocalhost: true + https: + enabled: true + useServiceAccountCredentials: true + insecureSkipVerify: true + nodeSelector: + node-role.kubernetes.io/master: "" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +kubeAdmProxy: + enabled: false + metricsPort: 10249 + component: kube-proxy + clients: + port: 10013 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +kubeAdmEtcd: + enabled: false + metricsPort: 2381 + component: kube-etcd + clients: + port: 10014 + useLocalhost: true + nodeSelector: + node-role.kubernetes.io/master: "" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +## rke2 PushProx Monitoring +## ref: https://github.com/rancher/charts/tree/dev-v2.9/packages/rancher-monitoring/rancher-pushprox +## +rke2ControllerManager: + enabled: false + metricsPort: 10257 # default to secure port as of k8s >= 1.22 + component: kube-controller-manager + clients: + https: + enabled: true + insecureSkipVerify: true + useServiceAccountCredentials: true + port: 10011 + useLocalhost: true + nodeSelector: + node-role.kubernetes.io/master: "true" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + kubeVersionOverrides: + - constraint: "< 1.22" + values: + metricsPort: 10252 # default to insecure port in k8s < 1.22 + clients: + https: + enabled: false + insecureSkipVerify: false + useServiceAccountCredentials: false + +rke2Scheduler: + enabled: false + metricsPort: 10259 # default to secure port as of k8s >= 1.22 + component: kube-scheduler + clients: + https: + enabled: true + insecureSkipVerify: true + useServiceAccountCredentials: true + port: 10012 + useLocalhost: true + nodeSelector: + node-role.kubernetes.io/master: "true" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + kubeVersionOverrides: + - constraint: "< 1.22" + values: + metricsPort: 10251 # default to insecure port in k8s < 1.22 + clients: + https: + enabled: false + insecureSkipVerify: false + useServiceAccountCredentials: false + +rke2Proxy: + enabled: false + metricsPort: 10249 + component: kube-proxy + clients: + port: 10013 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +rke2Etcd: + enabled: false + metricsPort: 2381 + component: kube-etcd + clients: + port: 10014 + useLocalhost: true + nodeSelector: + node-role.kubernetes.io/etcd: "true" + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +rke2IngressNginx: + enabled: false + metricsPort: 10254 + component: ingress-nginx + networkPolicy: + enabled: false + # in the RKE2 cluster, the ingress-nginx-controller is deployed + # as a non-hostNetwork workload starting at the following versions + # - >= v1.22.12+rke2r1 < 1.23.0-0 + # - >= v1.23.9+rke2r1 < 1.24.0-0 + # - >= v1.24.3+rke2r1 < 1.25.0-0 + # - >= v1.25.0+rke2r1 + # As a result we do not need clients and proxies as we can directly create + # a service that targets the workload with the given app name + namespaceOverride: kube-system + clients: + enabled: false + proxy: + enabled: false + service: + selector: + app.kubernetes.io/name: rke2-ingress-nginx + kubeVersionOverrides: + - constraint: "< 1.21.0-0" + values: + namespaceOverride: "" + clients: + enabled: true + port: 10015 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app.kubernetes.io/component" + operator: "In" + values: + - "controller" + topologyKey: "kubernetes.io/hostname" + namespaces: + - "kube-system" + # in the RKE2 cluster, the ingress-nginx-controller is deployed as + # a DaemonSet with 1 pod when RKE2 version is < 1.21.0-0 + deployment: + enabled: false + proxy: + enabled: true + service: + selector: false + - constraint: ">= 1.21.0-0 < 1.22.12-0" + values: + namespaceOverride: "" + clients: + enabled: true + port: 10015 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app.kubernetes.io/component" + operator: "In" + values: + - "controller" + topologyKey: "kubernetes.io/hostname" + namespaces: + - "kube-system" + # in the RKE2 cluster, the ingress-nginx-controller is deployed as + # a hostNetwork Deployment with 1 pod when RKE2 version is >= 1.21.0-0 + deployment: + enabled: true + replicas: 1 + proxy: + enabled: true + service: + selector: false + - constraint: ">= 1.23.0-0 < v1.23.9-0" + values: + namespaceOverride: "" + clients: + enabled: true + port: 10015 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app.kubernetes.io/component" + operator: "In" + values: + - "controller" + topologyKey: "kubernetes.io/hostname" + namespaces: + - "kube-system" + # in the RKE2 cluster, the ingress-nginx-controller is deployed as + # a hostNetwork Deployment with 1 pod when RKE2 version is >= 1.20.0-0 + deployment: + enabled: true + replicas: 1 + proxy: + enabled: true + service: + selector: false + - constraint: ">= 1.24.0-0 < v1.24.3-0" + values: + namespaceOverride: "" + clients: + enabled: true + port: 10015 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: "app.kubernetes.io/component" + operator: "In" + values: + - "controller" + topologyKey: "kubernetes.io/hostname" + namespaces: + - "kube-system" + # in the RKE2 cluster, the ingress-nginx-controller is deployed as + # a hostNetwork Deployment with 1 pod when RKE2 version is >= 1.20.0-0 + deployment: + enabled: true + replicas: 1 + proxy: + enabled: true + service: + selector: false + + + +## Additional PushProx Monitoring +## ref: https://github.com/rancher/charts/tree/dev-v2.9/packages/rancher-monitoring/rancher-pushprox +## + +# hardenedKubelet can only be deployed if kubelet.enabled=true +# If enabled, it replaces the ServiceMonitor deployed by the default kubelet option with a +# PushProx-based exporter that does not require a host port to be open to scrape metrics. +hardenedKubelet: + enabled: false + metricsPort: 10250 + component: kubelet + clients: + port: 10015 + useLocalhost: true + https: + enabled: true + useServiceAccountCredentials: true + insecureSkipVerify: true + rbac: + additionalRules: + - nonResourceURLs: ["/metrics/cadvisor"] + verbs: ["get"] + - apiGroups: [""] + resources: ["nodes/metrics"] + verbs: ["get"] + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + serviceMonitor: + endpoints: + - port: metrics + honorLabels: true + relabelings: + - sourceLabels: [__metrics_path__] + targetLabel: metrics_path + - port: metrics + path: /metrics/cadvisor + honorLabels: true + relabelings: + - sourceLabels: [__metrics_path__] + targetLabel: metrics_path + - port: metrics + path: /metrics/probes + honorLabels: true + relabelings: + - sourceLabels: [__metrics_path__] + targetLabel: metrics_path + +# hardenedNodeExporter can only be deployed if nodeExporter.enabled=true +# If enabled, it replaces the ServiceMonitor deployed by the default nodeExporter with a +# PushProx-based exporter that does not require a host port to be open to scrape metrics. +hardenedNodeExporter: + enabled: false + metricsPort: 9796 + component: node-exporter + clients: + port: 10016 + useLocalhost: true + tolerations: + - effect: "NoExecute" + operator: "Exists" + - effect: "NoSchedule" + operator: "Exists" + +## Upgrades +upgrade: + ## Run upgrade scripts before an upgrade or rollback via a Job hook + enabled: true + ## Image to use to run the scripts + image: + repository: rancher/shell + tag: v0.2.1 + +## Rancher Monitoring +## + +rancherMonitoring: + enabled: true + + ## A namespaceSelector to identify the namespace to find the Rancher deployment + ## + namespaceSelector: + matchNames: + - cattle-system + + ## A selector to identify the Rancher deployment + ## If not set, the chart will try to search for the Rancher deployment in the cattle-system namespace and infer the selector values from it + ## If the Rancher deployment does not exist, no resources will be deployed. + ## + selector: {} + +## Component scraping nginx-ingress-controller +## +ingressNginx: + enabled: false + + ## The namespace to search for your nginx-ingress-controller + ## + namespace: ingress-nginx + + service: + port: 9913 + targetPort: 10254 + # selector: + # app: ingress-nginx + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "30s" + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## metric relabel configs to apply to samples before ingestion. + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + # relabel configs to apply to samples before ingestion. + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + +# Prometheus Operator Configuration + +## Provide a name in place of kube-prometheus-stack for `app:` labels +## NOTE: If you change this value, you must update the prometheus-adapter.prometheus.url +## +nameOverride: "rancher-monitoring" + +## Override the deployment namespace +## NOTE: If you change this value, you must update the prometheus-adapter.prometheus.url +## +namespaceOverride: "cattle-monitoring-system" + +## Provide a k8s version to auto dashboard import script example: kubeTargetVersionOverride: 1.26.6 +## +kubeTargetVersionOverride: "" + +## Allow kubeVersion to be overridden while creating the ingress +## +kubeVersionOverride: "" + +## Provide a name to substitute for the full names of resources +## +fullnameOverride: "" + +## Labels to apply to all resources +## +commonLabels: {} +# scmhash: abc123 +# myLabel: aakkmd + +## Install Prometheus Operator CRDs +## +crds: + enabled: true + +## custom Rules to override "for" and "severity" in defaultRules +## +customRules: {} + # AlertmanagerFailedReload: + # for: 3m + # AlertmanagerMembersInconsistent: + # for: 5m + # severity: "warning" + +## Create default rules for monitoring the cluster +## +defaultRules: + create: true + rules: + alertmanager: true + etcd: true + configReloaders: true + general: true + k8sContainerCpuUsageSecondsTotal: true + k8sContainerMemoryCache: true + k8sContainerMemoryRss: true + k8sContainerMemorySwap: true + k8sContainerResource: true + k8sContainerMemoryWorkingSetBytes: true + k8sPodOwner: true + kubeApiserverAvailability: true + kubeApiserverBurnrate: true + kubeApiserverHistogram: true + kubeApiserverSlos: true + kubeControllerManager: true + kubelet: true + kubeProxy: true + kubePrometheusGeneral: true + kubePrometheusNodeRecording: true + kubernetesApps: true + kubernetesResources: true + kubernetesStorage: true + kubernetesSystem: true + kubeSchedulerAlerting: true + kubeSchedulerRecording: true + kubeStateMetrics: true + network: true + node: true + nodeExporterAlerting: true + nodeExporterRecording: true + prometheus: true + prometheusOperator: true + windows: true + + ## Reduce app namespace alert scope + appNamespacesTarget: ".*" + + ## Set keep_firing_for for all alerts + keepFiringFor: "" + + ## Labels for default rules + labels: {} + ## Annotations for default rules + annotations: {} + + ## Additional labels for PrometheusRule alerts + additionalRuleLabels: {} + + ## Additional annotations for PrometheusRule alerts + additionalRuleAnnotations: {} + + ## Additional labels for specific PrometheusRule alert groups + additionalRuleGroupLabels: + alertmanager: {} + etcd: {} + configReloaders: {} + general: {} + k8sContainerCpuUsageSecondsTotal: {} + k8sContainerMemoryCache: {} + k8sContainerMemoryRss: {} + k8sContainerMemorySwap: {} + k8sContainerResource: {} + k8sPodOwner: {} + kubeApiserverAvailability: {} + kubeApiserverBurnrate: {} + kubeApiserverHistogram: {} + kubeApiserverSlos: {} + kubeControllerManager: {} + kubelet: {} + kubeProxy: {} + kubePrometheusGeneral: {} + kubePrometheusNodeRecording: {} + kubernetesApps: {} + kubernetesResources: {} + kubernetesStorage: {} + kubernetesSystem: {} + kubeSchedulerAlerting: {} + kubeSchedulerRecording: {} + kubeStateMetrics: {} + network: {} + node: {} + nodeExporterAlerting: {} + nodeExporterRecording: {} + prometheus: {} + prometheusOperator: {} + + ## Additional annotations for specific PrometheusRule alerts groups + additionalRuleGroupAnnotations: + alertmanager: {} + etcd: {} + configReloaders: {} + general: {} + k8sContainerCpuUsageSecondsTotal: {} + k8sContainerMemoryCache: {} + k8sContainerMemoryRss: {} + k8sContainerMemorySwap: {} + k8sContainerResource: {} + k8sPodOwner: {} + kubeApiserverAvailability: {} + kubeApiserverBurnrate: {} + kubeApiserverHistogram: {} + kubeApiserverSlos: {} + kubeControllerManager: {} + kubelet: {} + kubeProxy: {} + kubePrometheusGeneral: {} + kubePrometheusNodeRecording: {} + kubernetesApps: {} + kubernetesResources: {} + kubernetesStorage: {} + kubernetesSystem: {} + kubeSchedulerAlerting: {} + kubeSchedulerRecording: {} + kubeStateMetrics: {} + network: {} + node: {} + nodeExporterAlerting: {} + nodeExporterRecording: {} + prometheus: {} + prometheusOperator: {} + + additionalAggregationLabels: [] + + ## Prefix for runbook URLs. Use this to override the first part of the runbookURLs that is common to all rules. + runbookUrl: "https://runbooks.prometheus-operator.dev/runbooks" + + ## Disabled PrometheusRule alerts + disabled: {} + # KubeAPIDown: true + # NodeRAIDDegraded: true + +## Deprecated way to provide custom recording or alerting rules to be deployed into the cluster. +## +# additionalPrometheusRules: [] +# - name: my-rule-file +# groups: +# - name: my_group +# rules: +# - record: my_record +# expr: 100 * my_record + +## Provide custom recording or alerting rules to be deployed into the cluster. +## +additionalPrometheusRulesMap: {} +# rule-name: +# groups: +# - name: my_group +# rules: +# - record: my_record +# expr: 100 * my_record + +## +global: + cattle: + + systemDefaultRegistry: "" + ## Windows Monitoring + ## ref: https://github.com/rancher/charts/tree/dev-v2.5-source/packages/rancher-windows-exporter + ## + ## Deploys a DaemonSet of Prometheus exporters based on https://github.com/prometheus-community/windows_exporter. + ## Every Windows host must have a wins version of 0.1.0+ to use this chart (default as of Rancher 2.5.8). + ## To upgrade wins versions on Windows hosts, see https://github.com/rancher/wins/tree/master/charts/rancher-wins-upgrader. + ## + windows: + enabled: false + seLinux: + enabled: false + kubectl: + repository: rancher/kubectl + tag: v1.29.2 + pullPolicy: IfNotPresent + rbac: + ## Create RBAC resources for ServiceAccounts and users + ## + create: true + + userRoles: + ## Create default user ClusterRoles to allow users to interact with Prometheus CRs, ConfigMaps, and Secrets + create: true + ## Aggregate default user ClusterRoles into default k8s ClusterRoles + aggregateToDefaultRoles: true + + ## Create ClusterRoles that extend the existing view, edit and admin ClusterRoles to interact with prometheus-operator CRDs + ## Ref: https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles + createAggregateClusterRoles: false + + pspAnnotations: {} + ## 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' + + ## Global image registry to use if it needs to be overriden for some specific use cases (e.g local registries, custom images, ...) + ## + imageRegistry: "docker.io" + + ## 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: [] + # - name: "image-pull-secret" + # or + # - "image-pull-secret" + +windowsMonitoring: + ## Deploys the windows-exporter and Windows-specific dashboards and rules (job name must be 'windows-exporter') + enabled: false + +loggingMonitors: + ## Deploys logging-specific dashboards, make sure to also set metrics.serviceMonitor to true in the logging chart for both fluentd and fluentbit + fluentd: + enabled: false + fluentbit: + enabled: false + +## Configuration for prometheus-windows-exporter +## ref: https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-windows-exporter +## +prometheus-windows-exporter: + ## Enable ServiceMonitor and set Kubernetes label to use as a job label + ## + prometheus: + monitor: + enabled: true + jobLabel: jobLabel + + releaseLabel: true + + ## Set job label to 'windows-exporter' as required by the default Prometheus rules and Grafana dashboards + ## + podLabels: + jobLabel: windows-exporter + + ## Enable memory and container metrics as required by the default Prometheus rules and Grafana dashboards + ## + config: |- + collectors: + enabled: '[defaults],memory,container' + +## Configuration for alertmanager +## ref: https://prometheus.io/docs/alerting/alertmanager/ +## +alertmanager: + + ## Deploy alertmanager + ## + enabled: true + + ## Annotations for Alertmanager + ## + annotations: {} + + ## Api that prometheus will use to communicate with alertmanager. Possible values are v1, v2 + ## + apiVersion: v2 + + ## @param alertmanager.enableFeatures Enable access to Alertmanager disabled features. + ## + enableFeatures: [] + + ## Service account for Alertmanager to use. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + create: true + name: "" + annotations: {} + automountServiceAccountToken: true + + ## Configure pod disruption budgets for Alertmanager + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget + ## + podDisruptionBudget: + enabled: false + minAvailable: 1 + maxUnavailable: "" + + ## Alertmanager configuration directives + ## ref: https://prometheus.io/docs/alerting/configuration/#configuration-file + ## https://prometheus.io/webtools/alerting/routing-tree-editor/ + ## + config: + global: + resolve_timeout: 5m + inhibit_rules: + - source_matchers: + - 'severity = critical' + target_matchers: + - 'severity =~ warning|info' + equal: + - 'namespace' + - 'alertname' + - source_matchers: + - 'severity = warning' + target_matchers: + - 'severity = info' + equal: + - 'namespace' + - 'alertname' + - source_matchers: + - 'alertname = InfoInhibitor' + target_matchers: + - 'severity = info' + equal: + - 'namespace' + - target_matchers: + - 'alertname = InfoInhibitor' + route: + group_by: ['namespace'] + group_wait: 30s + group_interval: 5m + repeat_interval: 12h + receiver: 'null' + routes: + - receiver: 'null' + matchers: + - alertname = "Watchdog" + receivers: + - name: 'null' + templates: + - '/etc/alertmanager/config/*.tmpl' + + ## Alertmanager configuration directives (as string type, preferred over the config hash map) + ## stringConfig will be used only, if tplConfig is true + ## ref: https://prometheus.io/docs/alerting/configuration/#configuration-file + ## https://prometheus.io/webtools/alerting/routing-tree-editor/ + ## + stringConfig: "" + + ## Pass the Alertmanager configuration directives through Helm's templating + ## engine. If the Alertmanager configuration contains Alertmanager templates, + ## they'll need to be properly escaped so that they are not interpreted by + ## Helm + ## ref: https://helm.sh/docs/developing_charts/#using-the-tpl-function + ## https://prometheus.io/docs/alerting/configuration/#tmpl_string + ## https://prometheus.io/docs/alerting/notifications/ + ## https://prometheus.io/docs/alerting/notification_examples/ + tplConfig: false + + ## Alertmanager template files to format alerts + ## By default, templateFiles are placed in /etc/alertmanager/config/ and if + ## they have a .tmpl file suffix will be loaded. See config.templates above + ## to change, add other suffixes. If adding other suffixes, be sure to update + ## config.templates above to include those suffixes. + ## ref: https://prometheus.io/docs/alerting/notifications/ + ## https://prometheus.io/docs/alerting/notification_examples/ + ## + templateFiles: + rancher_defaults.tmpl: |- + {{- define "slack.rancher.text" -}} + {{ template "rancher.text_multiple" . }} + {{- end -}} + + {{- define "rancher.text_multiple" -}} + *[GROUP - Details]* + One or more alarms in this group have triggered a notification. + + {{- if gt (len .GroupLabels.Values) 0 }} + *Group Labels:* + {{- range .GroupLabels.SortedPairs }} + • *{{ .Name }}:* `{{ .Value }}` + {{- end }} + {{- end }} + {{- if .ExternalURL }} + *Link to AlertManager:* {{ .ExternalURL }} + {{- end }} + + {{- range .Alerts }} + {{ template "rancher.text_single" . }} + {{- end }} + {{- end -}} + + {{- define "rancher.text_single" -}} + {{- if .Labels.alertname }} + *[ALERT - {{ .Labels.alertname }}]* + {{- else }} + *[ALERT]* + {{- end }} + {{- if .Labels.severity }} + *Severity:* `{{ .Labels.severity }}` + {{- end }} + {{- if .Labels.cluster }} + *Cluster:* {{ .Labels.cluster }} + {{- end }} + {{- if .Annotations.summary }} + *Summary:* {{ .Annotations.summary }} + {{- end }} + {{- if .Annotations.message }} + *Message:* {{ .Annotations.message }} + {{- end }} + {{- if .Annotations.description }} + *Description:* {{ .Annotations.description }} + {{- end }} + {{- if .Annotations.runbook_url }} + *Runbook URL:* <{{ .Annotations.runbook_url }}|:spiral_note_pad:> + {{- end }} + {{- with .Labels }} + {{- with .Remove (stringSlice "alertname" "severity" "cluster") }} + {{- if gt (len .) 0 }} + *Additional Labels:* + {{- range .SortedPairs }} + • *{{ .Name }}:* `{{ .Value }}` + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- with .Annotations }} + {{- with .Remove (stringSlice "summary" "message" "description" "runbook_url") }} + {{- if gt (len .) 0 }} + *Additional Annotations:* + {{- range .SortedPairs }} + • *{{ .Name }}:* `{{ .Value }}` + {{- end }} + {{- end }} + {{- end }} + {{- end }} + {{- end -}} + + ingress: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + + labels: {} + + ## Override ingress to a different defined port on the service + # servicePort: 8081 + ## Override ingress to a different service then the default, this is useful if you need to + ## point to a specific instance of the alertmanager (eg kube-prometheus-stack-alertmanager-0) + # serviceName: kube-prometheus-stack-alertmanager-0 + + ## Hosts must be provided if Ingress is enabled. + ## + hosts: [] + # - alertmanager.domain.com + + ## Paths to use for ingress rules - one path should match the alertmanagerSpec.routePrefix + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## TLS configuration for Alertmanager Ingress + ## Secret must be manually created in the namespace + ## + tls: [] + # - secretName: alertmanager-general-tls + # hosts: + # - alertmanager.example.com + + ## Configuration for Alertmanager secret + ## + secret: + annotations: {} + + # by default the alertmanager secret is not overwritten if it already exists + recreateIfExists: false + + ## Configuration for creating an Ingress that will map to each Alertmanager replica service + ## alertmanager.servicePerReplica must be enabled + ## + ingressPerReplica: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + labels: {} + + ## Final form of the hostname for each per replica ingress is + ## {{ ingressPerReplica.hostPrefix }}-{{ $replicaNumber }}.{{ ingressPerReplica.hostDomain }} + ## + ## Prefix for the per replica ingress that will have `-$replicaNumber` + ## appended to the end + hostPrefix: "" + ## Domain that will be used for the per replica ingress + hostDomain: "" + + ## Paths to use for ingress rules + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## Secret name containing the TLS certificate for alertmanager per replica ingress + ## Secret must be manually created in the namespace + tlsSecretName: "" + + ## Separated secret for each per replica Ingress. Can be used together with cert-manager + ## + tlsSecretPerReplica: + enabled: false + ## Final form of the secret for each per replica ingress is + ## {{ tlsSecretPerReplica.prefix }}-{{ $replicaNumber }} + ## + prefix: "alertmanager" + + ## Configuration for Alertmanager service + ## + service: + annotations: {} + labels: {} + clusterIP: "" + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + + ## Port for Alertmanager Service to listen on + ## + port: 9093 + ## To be used with a proxy extraContainer port + ## + targetPort: 9093 + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30903 + ## List of IP addresses at which the Prometheus server service is available + ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips + ## + + ## Additional ports to open for Alertmanager service + ## + additionalPorts: [] + # - name: oauth-proxy + # port: 8081 + # targetPort: 8081 + # - name: oauth-metrics + # port: 8082 + # targetPort: 8082 + + externalIPs: [] + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## If you want to make sure that connections from a particular client are passed to the same Pod each time + ## Accepts 'ClientIP' or 'None' + ## + sessionAffinity: None + + ## If you want to modify the ClientIP sessionAffinity timeout + ## The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP" + ## + sessionAffinityConfig: + clientIP: + timeoutSeconds: 10800 + + ## Service type + ## + type: ClusterIP + + ## Configuration for creating a separate Service for each statefulset Alertmanager replica + ## + servicePerReplica: + enabled: false + annotations: {} + + ## Port for Alertmanager Service per replica to listen on + ## + port: 9093 + + ## To be used with a proxy extraContainer port + targetPort: 9093 + + ## Port to expose on each node + ## Only used if servicePerReplica.type is 'NodePort' + ## + nodePort: 30904 + + ## Loadbalancer source IP ranges + ## Only used if servicePerReplica.type is "LoadBalancer" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: ClusterIP + + ## Configuration for creating a ServiceMonitor for AlertManager + ## + serviceMonitor: + ## If true, a ServiceMonitor will be created for the AlertManager service. + ## + selfMonitor: true + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## Additional labels + ## + additionalLabels: {} + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS. + scheme: "" + + ## enableHttp2: Whether to enable HTTP2. + ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#endpoint + enableHttp2: true + + ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS. + ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig + tlsConfig: {} + + bearerTokenFile: + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional Endpoints + ## + additionalEndpoints: [] + # - port: oauth-metrics + # path: /metrics + + ## Settings affecting alertmanagerSpec + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerspec + ## + alertmanagerSpec: + ## Standard object's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata + ## Metadata Labels and Annotations gets propagated to the Alertmanager pods. + ## + podMetadata: {} + + ## Image of Alertmanager + ## + image: + repository: rancher/mirrored-prometheus-alertmanager + tag: v0.27.0 + sha: "" + + ## If true then the user will be responsible to provide a secret with alertmanager configuration + ## So when true the config part will be ignored (including templateFiles) and the one in the secret will be used + ## + useExistingSecret: false + + ## Secrets is a list of Secrets in the same namespace as the Alertmanager object, which shall be mounted into the + ## Alertmanager Pods. The Secrets are mounted into /etc/alertmanager/secrets/. + ## + secrets: [] + + ## If false then the user will opt out of automounting API credentials. + ## + automountServiceAccountToken: true + + ## ConfigMaps is a list of ConfigMaps in the same namespace as the Alertmanager object, which shall be mounted into the Alertmanager Pods. + ## The ConfigMaps are mounted into /etc/alertmanager/configmaps/. + ## + configMaps: [] + + ## ConfigSecret is the name of a Kubernetes Secret in the same namespace as the Alertmanager object, which contains configuration for + ## this Alertmanager instance. Defaults to 'alertmanager-' The secret is mounted into /etc/alertmanager/config. + ## + # configSecret: + + ## WebTLSConfig defines the TLS parameters for HTTPS + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerwebspec + web: {} + + ## AlertmanagerConfigs to be selected to merge and configure Alertmanager with. + ## + alertmanagerConfigSelector: {} + ## Example which selects all alertmanagerConfig resources + ## with label "alertconfig" with values any of "example-config" or "example-config-2" + # alertmanagerConfigSelector: + # matchExpressions: + # - key: alertconfig + # operator: In + # values: + # - example-config + # - example-config-2 + # + ## Example which selects all alertmanagerConfig resources with label "role" set to "example-config" + # alertmanagerConfigSelector: + # matchLabels: + # role: example-config + + ## Namespaces to be selected for AlertmanagerConfig discovery. If nil, only check own namespace. + ## + alertmanagerConfigNamespaceSelector: {} + ## Example which selects all namespaces + ## with label "alertmanagerconfig" with values any of "example-namespace" or "example-namespace-2" + # alertmanagerConfigNamespaceSelector: + # matchExpressions: + # - key: alertmanagerconfig + # operator: In + # values: + # - example-namespace + # - example-namespace-2 + + ## Example which selects all namespaces with label "alertmanagerconfig" set to "enabled" + # alertmanagerConfigNamespaceSelector: + # matchLabels: + # alertmanagerconfig: enabled + + ## AlermanagerConfig to be used as top level configuration + ## + alertmanagerConfiguration: {} + ## Example with select a global alertmanagerconfig + # alertmanagerConfiguration: + # name: global-alertmanager-Configuration + + ## Defines the strategy used by AlertmanagerConfig objects to match alerts. eg: + ## + alertmanagerConfigMatcherStrategy: {} + ## Example with use OnNamespace strategy + # alertmanagerConfigMatcherStrategy: + # type: OnNamespace + + ## Define Log Format + # Use logfmt (default) or json logging + logFormat: logfmt + + ## Log level for Alertmanager to be configured with. + ## + logLevel: info + + ## Size is the expected size of the alertmanager cluster. The controller will eventually make the size of the + ## running cluster equal to the expected size. + replicas: 1 + + ## Time duration Alertmanager shall retain data for. Default is '120h', and must match the regular expression + ## [0-9]+(ms|s|m|h) (milliseconds seconds minutes hours). + ## + retention: 120h + + ## Storage is the definition of how storage will be used by the Alertmanager instances. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md + ## + storage: {} + # volumeClaimTemplate: + # spec: + # storageClassName: gluster + # accessModes: ["ReadWriteOnce"] + # resources: + # requests: + # storage: 50Gi + # selector: {} + + + ## The external URL the Alertmanager instances will be available under. This is necessary to generate correct URLs. This is necessary if Alertmanager is not served from root of a DNS name. string false + ## + externalUrl: + + ## The route prefix Alertmanager registers HTTP handlers for. This is useful, if using ExternalURL and a proxy is rewriting HTTP routes of a request, and the actual ExternalURL is still true, + ## but the server serves requests under a different route prefix. For example for use with kubectl proxy. + ## + routePrefix: / + + ## scheme: HTTP scheme to use. Can be used with `tlsConfig` for example if using istio mTLS. + scheme: "" + + ## tlsConfig: TLS configuration to use when connect to the endpoint. For example if using istio mTLS. + ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig + tlsConfig: {} + + ## If set to true all actions on the underlying managed objects are not going to be performed, except for delete actions. + ## + paused: false + + ## Define which Nodes the Pods are scheduled on. + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Define resources requests and limits for single Pods. + ## ref: https://kubernetes.io/docs/user-guide/compute-resources/ + ## + resources: + limits: + memory: 500Mi + cpu: 1000m + requests: + memory: 100Mi + cpu: 100m + + ## Pod anti-affinity can prevent the scheduler from placing Prometheus replicas on the same node. + ## The default value "soft" means that the scheduler should *prefer* to not schedule two replica pods onto the same node but no guarantee is provided. + ## The value "hard" means that the scheduler is *required* to not schedule two replica pods onto the same node. + ## The value "" will disable pod anti-affinity so that no anti-affinity rules will be configured. + ## + podAntiAffinity: "" + + ## If anti-affinity is enabled sets the topologyKey to use for anti-affinity. + ## This can be changed to, for example, failure-domain.beta.kubernetes.io/zone + ## + podAntiAffinityTopologyKey: kubernetes.io/hostname + + ## Assign custom affinity rules to the alertmanager instance + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + affinity: {} + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/e2e-az-name + # operator: In + # values: + # - e2e-az1 + # - e2e-az2 + + ## If specified, the pod's tolerations. + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + # - key: "key" + # operator: "Equal" + # value: "value" + # effect: "NoSchedule" + + ## If specified, the pod's topology spread constraints. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app: alertmanager + + ## SecurityContext holds pod-level security attributes and common container settings. + ## This defaults to non root user with uid 1000 and gid 2000. *v1.PodSecurityContext false + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 2000 + seccompProfile: + type: RuntimeDefault + + ## ListenLocal makes the Alertmanager server listen on loopback, so that it does not bind against the Pod IP. + ## Note this is only for the Alertmanager UI, not the gossip communication. + ## + listenLocal: false + + ## Containers allows injecting additional containers. This is meant to allow adding an authentication proxy to an Alertmanager pod. + ## + containers: [] + # containers: + # - name: oauth-proxy + # image: quay.io/oauth2-proxy/oauth2-proxy:v7.5.1 + # args: + # - --upstream=http://127.0.0.1:9093 + # - --http-address=0.0.0.0:8081 + # - --metrics-address=0.0.0.0:8082 + # - ... + # ports: + # - containerPort: 8081 + # name: oauth-proxy + # protocol: TCP + # - containerPort: 8082 + # name: oauth-metrics + # protocol: TCP + # resources: {} + + # Additional volumes on the output StatefulSet definition. + volumes: [] + + # Additional VolumeMounts on the output StatefulSet definition. + volumeMounts: [] + + ## InitContainers allows injecting additional initContainers. This is meant to allow doing some changes + ## (permissions, dir tree) on mounted volumes before starting prometheus + initContainers: [] + + ## Priority class assigned to the Pods + ## + priorityClassName: "" + + ## AdditionalPeers allows injecting a set of additional Alertmanagers to peer with to form a highly available cluster. + ## + additionalPeers: [] + + ## PortName to use for Alert Manager. + ## + portName: "http-web" + + ## ClusterAdvertiseAddress is the explicit address to advertise in cluster. Needs to be provided for non RFC1918 [1] (public) addresses. [1] RFC1918: https://tools.ietf.org/html/rfc1918 + ## + clusterAdvertiseAddress: false + + ## clusterGossipInterval determines interval between gossip attempts. + ## Needs to be specified as GoDuration, a time duration that can be parsed by Go’s time.ParseDuration() (e.g. 45ms, 30s, 1m, 1h20m15s) + clusterGossipInterval: "" + + ## clusterPeerTimeout determines timeout for cluster peering. + ## Needs to be specified as GoDuration, a time duration that can be parsed by Go’s time.ParseDuration() (e.g. 45ms, 30s, 1m, 1h20m15s) + clusterPeerTimeout: "" + + ## clusterPushpullInterval determines interval between pushpull attempts. + ## Needs to be specified as GoDuration, a time duration that can be parsed by Go’s time.ParseDuration() (e.g. 45ms, 30s, 1m, 1h20m15s) + clusterPushpullInterval: "" + + ## ForceEnableClusterMode ensures Alertmanager does not deactivate the cluster mode when running with a single replica. + ## Use case is e.g. spanning an Alertmanager cluster across Kubernetes clusters with a single replica in each. + forceEnableClusterMode: false + + ## Minimum number of seconds for which a newly created pod should be ready without any of its container crashing for it to + ## be considered available. Defaults to 0 (pod will be considered available as soon as it is ready). + minReadySeconds: 0 + + ## Additional configuration which is not covered by the properties above. (passed through tpl) + additionalConfig: {} + + ## Additional configuration which is not covered by the properties above. + ## Useful, if you need advanced templating inside alertmanagerSpec. + ## Otherwise, use alertmanager.alertmanagerSpec.additionalConfig (passed through tpl) + additionalConfigString: "" + + ## ExtraSecret can be used to store various data in an extra secret + ## (use it for example to store hashed basic auth credentials) + extraSecret: + ## if not set, name will be auto generated + # name: "" + annotations: {} + data: {} + # auth: | + # foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0 + # someoneelse:$apr1$DMZX2Z4q$6SbQIfyuLQd.xmo/P0m2c. + +## Using default values from https://github.com/grafana/helm-charts/blob/main/charts/grafana/values.yaml +## +grafana: + enabled: true + namespaceOverride: "" + + ## Grafana's primary configuration + ## NOTE: values in map will be converted to ini format + ## ref: http://docs.grafana.org/installation/configuration/ + ## + grafana.ini: + users: + auto_assign_org_role: Viewer + auth: + disable_login_form: false + auth.anonymous: + enabled: true + org_role: Viewer + auth.basic: + enabled: false + dashboards: + # Modify this value to change the default dashboard shown on the main Grafana page + default_home_dashboard_path: /tmp/dashboards/rancher-default-home.json + security: + # Required to embed dashboards in Rancher Cluster Overview Dashboard on Cluster Explorer + allow_embedding: true + + deploymentStrategy: + type: Recreate + + ## ForceDeployDatasources Create datasource configmap even if grafana deployment has been disabled + ## + forceDeployDatasources: false + + ## ForceDeployDashboard Create dashboard configmap even if grafana deployment has been disabled + ## + forceDeployDashboards: false + + ## Deploy default dashboards + ## + defaultDashboardsEnabled: true + + # Additional options for defaultDashboards + defaultDashboards: + # The default namespace to place defaultDashboards within + namespace: cattle-dashboards + # Whether to create the default namespace as a Helm managed namespace or use an existing namespace + # If false, the defaultDashboards.namespace will be created as a Helm managed namespace + useExistingNamespace: false + # Whether the Helm managed namespace created by this chart should be left behind on a Helm uninstall + # If you place other dashboards in this namespace, then they will be deleted on a helm uninstall + # Ignore if useExistingNamespace is true + cleanupOnUninstall: false + + ## Timezone for the default dashboards + ## Other options are: browser or a specific timezone, i.e. Europe/Luxembourg + ## + defaultDashboardsTimezone: utc + + ## Editable flag for the default dashboards + ## + defaultDashboardsEditable: true + + adminPassword: prom-operator + + rbac: + ## If true, Grafana PSPs will be created + ## + pspEnabled: false + + ingress: + ## If true, Grafana Ingress will be created + ## + enabled: false + + ## IngressClassName for Grafana Ingress. + ## Should be provided if Ingress is enable. + ## + # ingressClassName: nginx + + ## Annotations for Grafana Ingress + ## + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + + ## Labels to be added to the Ingress + ## + labels: {} + + ## Hostnames. + ## Must be provided if Ingress is enable. + ## + # hosts: + # - grafana.domain.com + hosts: [] + + ## Path for grafana ingress + path: / + + ## TLS configuration for grafana Ingress + ## Secret must be manually created in the namespace + ## + tls: [] + # - secretName: grafana-general-tls + # hosts: + # - grafana.example.com + + # # To make Grafana persistent (Using Statefulset) + # # + # persistence: + # enabled: true + # type: sts + # storageClassName: "storageClassName" + # accessModes: + # - ReadWriteOnce + # size: 20Gi + # finalizers: + # - kubernetes.io/pvc-protection + + serviceAccount: + create: true + autoMount: true + + sidecar: + dashboards: + enabled: true + label: grafana_dashboard + searchNamespace: cattle-dashboards + labelValue: "1" + + # Support for new table panels, when enabled grafana auto migrates the old table panels to newer table panels + enableNewTablePanelSyntax: false + + ## Annotations for Grafana dashboard configmaps + ## + annotations: {} + multicluster: + global: + enabled: false + etcd: + enabled: false + provider: + allowUiUpdates: false + datasources: + enabled: true + defaultDatasourceEnabled: true + isDefaultDatasource: true + + name: Prometheus + uid: prometheus + + ## URL of prometheus datasource + ## + # url: http://prometheus-stack-prometheus:9090/ + + ## Prometheus request timeout in seconds + # timeout: 30 + + # If not defined, will use prometheus.prometheusSpec.scrapeInterval or its default + # defaultDatasourceScrapeInterval: 15s + + ## Annotations for Grafana datasource configmaps + ## + annotations: {} + + ## Set method for HTTP to send query to datasource + httpMethod: POST + + ## Create datasource for each Pod of Prometheus StatefulSet; + ## this uses headless service `prometheus-operated` which is + ## created by Prometheus Operator + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/0fee93e12dc7c2ea1218f19ae25ec6b893460590/pkg/prometheus/statefulset.go#L255-L286 + createPrometheusReplicasDatasources: false + label: grafana_datasource + labelValue: "1" + + ## Field with internal link pointing to existing data source in Grafana. + ## Can be provisioned via additionalDataSources + exemplarTraceIdDestinations: {} + # datasourceUid: Jaeger + # traceIdLabelName: trace_id + alertmanager: + enabled: true + name: Alertmanager + uid: alertmanager + handleGrafanaManagedAlerts: false + implementation: prometheus + + extraConfigmapMounts: [] + # - name: certs-configmap + # mountPath: /etc/grafana/ssl/ + # configMap: certs-configmap + # readOnly: true + + deleteDatasources: [] + # - name: example-datasource + # orgId: 1 + + ## Configure additional grafana datasources (passed through tpl) + ## ref: http://docs.grafana.org/administration/provisioning/#datasources + additionalDataSources: [] + # - name: prometheus-sample + # access: proxy + # basicAuth: true + # basicAuthPassword: pass + # basicAuthUser: daco + # editable: false + # jsonData: + # tlsSkipVerify: true + # orgId: 1 + # type: prometheus + # url: https://{{ printf "%s-prometheus.svc" .Release.Name }}:9090 + # version: 1 + + ## Passed to grafana subchart and used by servicemonitor below + ## + service: + portName: nginx-http + ## Port for Grafana Service to listen on + ## + port: 80 + ## To be used with a proxy extraContainer port + ## + targetPort: 8080 + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30950 + ## Service type + ## + type: ClusterIP + + ipFamilies: [] + ipFamilyPolicy: "" + + proxy: + image: + repository: rancher/mirrored-library-nginx + tag: 1.24.0-alpine + + ## Enable an Specify container in extraContainers. This is meant to allow adding an authentication proxy to a grafana pod + extraContainers: | + - name: grafana-proxy + args: + - nginx + - -g + - daemon off; + - -c + - /nginx/nginx.conf + image: "{{ template "system_default_registry" . }}{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }}" + ports: + - containerPort: 8080 + name: nginx-http + protocol: TCP + volumeMounts: + - mountPath: /nginx + name: grafana-nginx + - mountPath: /var/cache/nginx + name: nginx-home + securityContext: + runAsUser: 101 + runAsGroup: 101 + + ## Volumes that can be used in containers + extraContainerVolumes: + - name: nginx-home + emptyDir: {} + - name: grafana-nginx + configMap: + name: grafana-nginx-proxy-config + items: + - key: nginx.conf + mode: 438 + path: nginx.conf + + ## If true, create a serviceMonitor for grafana + ## + serviceMonitor: + # If true, a ServiceMonitor CRD is created for a prometheus operator + # https://github.com/coreos/prometheus-operator + # + enabled: true + + # Path to use for scraping metrics. Might be different if server.root_url is set + # in grafana.ini + path: "/metrics" + + # namespace: monitoring (defaults to use the namespace this chart is deployed to) + + # labels for the ServiceMonitor + labels: {} + + # Scrape interval. If not set, the Prometheus default scrape interval is used. + # + interval: "" + scheme: http + tlsConfig: {} + scrapeTimeout: 30s + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + resources: + limits: + memory: 200Mi + cpu: 200m + requests: + memory: 100Mi + cpu: 100m + + testFramework: + enabled: false + +## Flag to disable all the kubernetes component scrapers +## +kubernetesServiceMonitors: + enabled: true + +## Component scraping the kube api server +## +kubeApiServer: + enabled: true + tlsConfig: + serverName: kubernetes + insecureSkipVerify: false + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + jobLabel: component + selector: + matchLabels: + component: apiserver + provider: kubernetes + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: + # Drop excessively noisy apiserver buckets. + - action: drop + regex: apiserver_request_duration_seconds_bucket;(0.15|0.2|0.3|0.35|0.4|0.45|0.6|0.7|0.8|0.9|1.25|1.5|1.75|2|3|3.5|4|4.5|6|7|8|9|15|25|40|50) + sourceLabels: + - __name__ + - le + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: + # - __meta_kubernetes_namespace + # - __meta_kubernetes_service_name + # - __meta_kubernetes_endpoint_port_name + # action: keep + # regex: default;kubernetes;https + # - targetLabel: __address__ + # replacement: kubernetes.default.svc:443 + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping the kubelet and kubelet-hosted cAdvisor +## +kubelet: + enabled: true + namespace: kube-system + + serviceMonitor: + ## Attach metadata to discovered targets. Requires Prometheus v2.45 for endpoints created by the operator. + ## + attachMetadata: + node: false + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## If true, Prometheus use (respect) labels provided by exporter. + ## + honorLabels: true + + ## If true, Prometheus ingests metrics with timestamp provided by exporter. If false, Prometheus ingests metrics with timestamp of scrape. + ## + honorTimestamps: true + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## Enable scraping the kubelet over https. For requirements to enable this see + ## https://github.com/prometheus-operator/prometheus-operator/issues/926 + ## + https: true + + ## Skip TLS certificate validation when scraping. + ## This is enabled by default because kubelet serving certificate deployed by kubeadm is by default self-signed + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/#kubelet-serving-certs + ## + insecureSkipVerify: true + + ## Enable scraping /metrics/cadvisor from kubelet's service + ## + cAdvisor: true + + ## Enable scraping /metrics/probes from kubelet's service + ## + probes: true + + ## Enable scraping /metrics/resource from kubelet's service + ## This is disabled by default because container metrics are already exposed by cAdvisor + ## + resource: false + # From kubernetes 1.18, /metrics/resource/v1alpha1 renamed to /metrics/resource + resourcePath: "/metrics/resource/v1alpha1" + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + cAdvisorMetricRelabelings: + # Drop less useful container CPU metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_cpu_(cfs_throttled_seconds_total|load_average_10s|system_seconds_total|user_seconds_total)' + # Drop less useful container / always zero filesystem metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_fs_(io_current|io_time_seconds_total|io_time_weighted_seconds_total|reads_merged_total|sector_reads_total|sector_writes_total|writes_merged_total)' + # Drop less useful / always zero container memory metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_memory_(mapped_file|swap)' + # Drop less useful container process metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_(file_descriptors|tasks_state|threads_max)' + # Drop container spec metrics that overlap with kube-state-metrics. + - sourceLabels: [__name__] + action: drop + regex: 'container_spec.*' + # Drop cgroup metrics with no pod. + - sourceLabels: [id, pod] + action: drop + regex: '.+;' + # - sourceLabels: [__name__, image] + # separator: ; + # regex: container_([a-z_]+); + # replacement: $1 + # action: drop + # - sourceLabels: [__name__] + # separator: ; + # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s) + # replacement: $1 + # action: drop + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + probesMetricRelabelings: [] + # - sourceLabels: [__name__, image] + # separator: ; + # regex: container_([a-z_]+); + # replacement: $1 + # action: drop + # - sourceLabels: [__name__] + # separator: ; + # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s) + # replacement: $1 + # action: drop + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + ## metrics_path is required to match upstream rules and charts + cAdvisorRelabelings: + - action: replace + sourceLabels: [__metrics_path__] + targetLabel: metrics_path + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + probesRelabelings: + - action: replace + sourceLabels: [__metrics_path__] + targetLabel: metrics_path + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + resourceRelabelings: + - action: replace + sourceLabels: [__metrics_path__] + targetLabel: metrics_path + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - sourceLabels: [__name__, image] + # separator: ; + # regex: container_([a-z_]+); + # replacement: $1 + # action: drop + # - sourceLabels: [__name__] + # separator: ; + # regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s) + # replacement: $1 + # action: drop + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + ## metrics_path is required to match upstream rules and charts + relabelings: + - action: replace + sourceLabels: [__metrics_path__] + targetLabel: metrics_path + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping the kube controller manager +## +kubeControllerManager: + enabled: false + + ## If your kube controller manager is not deployed as a pod, specify IPs it can be found on + ## + endpoints: [] + # - 10.141.4.22 + # - 10.141.4.23 + # - 10.141.4.24 + + ## If using kubeControllerManager.endpoints only the port and targetPort are used + ## + service: + enabled: true + ## If null or unset, the value is determined dynamically based on target Kubernetes version due to change + ## of default port in Kubernetes 1.22. + ## + port: null + targetPort: null + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + # selector: + # component: kube-controller-manager + + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## port: Name of the port the metrics will be scraped from + ## + port: http-metrics + + jobLabel: jobLabel + selector: {} + # matchLabels: + # component: kube-controller-manager + + ## Enable scraping kube-controller-manager over https. + ## Requires proper certs (not self-signed) and delegated authentication/authorization checks. + ## If null or unset, the value is determined dynamically based on target Kubernetes version. + ## + https: null + + # Skip TLS certificate validation when scraping + insecureSkipVerify: null + + # Name of the server to use when validating TLS certificate + serverName: null + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping coreDns. Use either this or kubeDns +## +coreDns: + enabled: true + service: + enabled: true + port: 9153 + targetPort: 9153 + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + # selector: + # k8s-app: kube-dns + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## port: Name of the port the metrics will be scraped from + ## + port: http-metrics + + jobLabel: jobLabel + selector: {} + # matchLabels: + # k8s-app: kube-dns + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping kubeDns. Use either this or coreDns +## +kubeDns: + enabled: false + service: + dnsmasq: + port: 10054 + targetPort: 10054 + skydns: + port: 10055 + targetPort: 10055 + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + # selector: + # k8s-app: kube-dns + serviceMonitor: + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + jobLabel: jobLabel + selector: {} + # matchLabels: + # k8s-app: kube-dns + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + dnsmasqMetricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + dnsmasqRelabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping etcd +## +kubeEtcd: + enabled: false + + ## If your etcd is not deployed as a pod, specify IPs it can be found on + ## + endpoints: [] + # - 10.141.4.22 + # - 10.141.4.23 + # - 10.141.4.24 + + ## Etcd service. If using kubeEtcd.endpoints only the port and targetPort are used + ## + service: + enabled: true + port: 2381 + targetPort: 2381 + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + # selector: + # component: etcd + + ## Configure secure access to the etcd cluster by loading a secret into prometheus and + ## specifying security configuration below. For example, with a secret named etcd-client-cert + ## + ## serviceMonitor: + ## scheme: https + ## insecureSkipVerify: false + ## serverName: localhost + ## caFile: /etc/prometheus/secrets/etcd-client-cert/etcd-ca + ## certFile: /etc/prometheus/secrets/etcd-client-cert/etcd-client + ## keyFile: /etc/prometheus/secrets/etcd-client-cert/etcd-client-key + ## + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + scheme: http + insecureSkipVerify: false + serverName: "" + caFile: "" + certFile: "" + keyFile: "" + + ## port: Name of the port the metrics will be scraped from + ## + port: http-metrics + + jobLabel: jobLabel + selector: {} + # matchLabels: + # component: etcd + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping kube scheduler +## +kubeScheduler: + enabled: false + + ## If your kube scheduler is not deployed as a pod, specify IPs it can be found on + ## + endpoints: [] + # - 10.141.4.22 + # - 10.141.4.23 + # - 10.141.4.24 + + ## If using kubeScheduler.endpoints only the port and targetPort are used + ## + service: + enabled: true + ## If null or unset, the value is determined dynamically based on target Kubernetes version due to change + ## of default port in Kubernetes 1.23. + ## + port: null + targetPort: null + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + # selector: + # component: kube-scheduler + + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + ## Enable scraping kube-scheduler over https. + ## Requires proper certs (not self-signed) and delegated authentication/authorization checks. + ## If null or unset, the value is determined dynamically based on target Kubernetes version. + ## + https: null + + ## port: Name of the port the metrics will be scraped from + ## + port: http-metrics + + jobLabel: jobLabel + selector: {} + # matchLabels: + # component: kube-scheduler + + ## Skip TLS certificate validation when scraping + insecureSkipVerify: null + + ## Name of the server to use when validating TLS certificate + serverName: null + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping kube proxy +## +kubeProxy: + enabled: false + + ## If your kube proxy is not deployed as a pod, specify IPs it can be found on + ## + endpoints: [] + # - 10.141.4.22 + # - 10.141.4.23 + # - 10.141.4.24 + + service: + enabled: true + port: 10249 + targetPort: 10249 + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + # selector: + # k8s-app: kube-proxy + + serviceMonitor: + enabled: true + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## port: Name of the port the metrics will be scraped from + ## + port: http-metrics + + jobLabel: jobLabel + selector: {} + # matchLabels: + # k8s-app: kube-proxy + + ## Enable scraping kube-proxy over https. + ## Requires proper certs (not self-signed) and delegated authentication/authorization checks + ## + https: false + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## Additional labels + ## + additionalLabels: {} + # foo: bar + +## Component scraping kube state metrics +## +kubeStateMetrics: + enabled: true + +## Configuration for kube-state-metrics subchart +## +kube-state-metrics: + namespaceOverride: "" + rbac: + create: true + releaseLabel: true + prometheus: + monitor: + enabled: true + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## Scrape Timeout. If not set, the Prometheus default scrape timeout is used. + ## + scrapeTimeout: "" + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + # Keep labels from scraped data, overriding server-side labels + ## + honorLabels: true + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + selfMonitor: + enabled: false + +## Deploy node exporter as a daemonset to all nodes +## +nodeExporter: + enabled: true + operatingSystems: + linux: + enabled: true + darwin: + enabled: true + + ## ForceDeployDashboard Create dashboard configmap even if nodeExporter deployment has been disabled + ## + forceDeployDashboards: false + +## Configuration for prometheus-node-exporter subchart +## +prometheus-node-exporter: + namespaceOverride: "" + podLabels: + ## Add the 'node-exporter' label to be used by serviceMonitor to match standard common usage in rules and grafana dashboards + ## + jobLabel: node-exporter + releaseLabel: true + extraArgs: + - --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|var/lib/docker/.+|var/lib/kubelet/.+)($|/) + - --collector.filesystem.fs-types-exclude=^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$ + service: + portName: http-metrics + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + prometheus: + monitor: + enabled: true + + jobLabel: jobLabel + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## How long until a scrape request times out. If not set, the Prometheus default scape timeout is used. + ## + scrapeTimeout: "" + + ## proxyUrl: URL of a proxy that should be used for scraping. + ## + proxyUrl: "" + + ## MetricRelabelConfigs to apply to samples after scraping, but before ingestion. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + metricRelabelings: [] + # - sourceLabels: [__name__] + # separator: ; + # regex: ^node_mountstats_nfs_(event|operations|transport)_.+ + # replacement: $1 + # action: drop + + ## RelabelConfigs to apply to samples before scraping + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + rbac: + ## If true, create PSPs for node-exporter + ## + pspEnabled: false + +## Manages Prometheus and Alertmanager components +## +prometheusOperator: + enabled: true + + ## Use '{{ template "kube-prometheus-stack.fullname" . }}-operator' by default + fullnameOverride: "" + + ## Number of old replicasets to retain ## + ## The default value is 10, 0 will garbage-collect old replicasets ## + revisionHistoryLimit: 10 + + ## Strategy of the deployment + ## + strategy: {} + + ## Prometheus-Operator v0.39.0 and later support TLS natively. + ## + tls: + enabled: true + # Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants + tlsMinVersion: VersionTLS13 + # The default webhook port is 10250 in order to work out-of-the-box in GKE private clusters and avoid adding firewall rules. + internalPort: 10250 + + ## Admission webhook support for PrometheusRules resources added in Prometheus Operator 0.30 can be enabled to prevent incorrectly formatted + ## rules from making their way into prometheus and potentially preventing the container from starting + admissionWebhooks: + ## Valid values: Fail, Ignore, IgnoreOnInstallOnly + ## IgnoreOnInstallOnly - If Release.IsInstall returns "true", set "Ignore" otherwise "Fail" + failurePolicy: "" + ## The default timeoutSeconds is 10 and the maximum value is 30. + timeoutSeconds: 10 + enabled: true + ## A PEM encoded CA bundle which will be used to validate the webhook's server certificate. + ## If unspecified, system trust roots on the apiserver are used. + caBundle: "" + ## If enabled, generate a self-signed certificate, then patch the webhook configurations with the generated data. + ## On chart upgrades (or if the secret exists) the cert will not be re-generated. You can use this to provide your own + ## certs ahead of time if you wish. + ## + annotations: {} + # argocd.argoproj.io/hook: PreSync + # argocd.argoproj.io/hook-delete-policy: HookSucceeded + + namespaceSelector: {} + objectSelector: {} + + + deployment: + enabled: false + + ## Number of replicas + ## + replicas: 1 + + ## Strategy of the deployment + ## + strategy: {} + + # Ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/ + podDisruptionBudget: {} + # maxUnavailable: 1 + # minAvailable: 1 + + ## Number of old replicasets to retain ## + ## The default value is 10, 0 will garbage-collect old replicasets ## + revisionHistoryLimit: 10 + + ## Prometheus-Operator v0.39.0 and later support TLS natively. + ## + tls: + enabled: true + # Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants + tlsMinVersion: VersionTLS13 + # The default webhook port is 10250 in order to work out-of-the-box in GKE private clusters and avoid adding firewall rules. + internalPort: 10250 + + ## Service account for Prometheus Operator Webhook to use. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + automountServiceAccountToken: false + create: true + name: "" + + ## Configuration for Prometheus operator Webhook service + ## + service: + annotations: {} + labels: {} + clusterIP: "" + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 31080 + + nodePortTls: 31443 + + ## Additional ports to open for Prometheus operator Webhook service + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services + ## + additionalPorts: [] + + ## Loadbalancer IP + ## Only use if service.type is "LoadBalancer" + ## + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## NodePort, ClusterIP, LoadBalancer + ## + type: ClusterIP + + ## List of IP addresses at which the Prometheus server service is available + ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips + ## + externalIPs: [] + + # ## Labels to add to the operator webhook deployment + # ## + labels: {} + + ## Annotations to add to the operator webhook deployment + ## + annotations: {} + + ## Labels to add to the operator webhook pod + ## + podLabels: {} + + ## Annotations to add to the operator webhook pod + ## + podAnnotations: {} + + ## Assign a PriorityClassName to pods if set + # priorityClassName: "" + + ## Define Log Format + # Use logfmt (default) or json logging + # logFormat: logfmt + + ## Decrease log verbosity to errors only + # logLevel: error + + ## Prometheus-operator webhook image + ## + image: + registry: quay.io + repository: rancher/mirrored-prometheus-operator-admission-webhook + # if not set appVersion field from Chart.yaml is used + tag: v0.75.1 + sha: "" + pullPolicy: IfNotPresent + + ## Define Log Format + # Use logfmt (default) or json logging + # logFormat: logfmt + + ## Decrease log verbosity to errors only + # logLevel: error + + + ## Liveness probe + ## + livenessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + + ## Readiness probe + ## + readinessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + + ## Resource limits & requests + ## + resources: {} + # limits: + # cpu: 200m + # memory: 200Mi + # requests: + # cpu: 100m + # memory: 100Mi + + # Required for use in managed kubernetes clusters (such as AWS EKS) with custom CNI (such as calico), + # because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working + ## + hostNetwork: false + + ## Define which Nodes the Pods are scheduled on. + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for use with node taints + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + # - key: "key" + # operator: "Equal" + # value: "value" + # effect: "NoSchedule" + + ## Assign custom affinity rules to the prometheus operator + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + affinity: {} + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/e2e-az-name + # operator: In + # values: + # - e2e-az1 + # - e2e-az2 + dnsConfig: {} + # nameservers: + # - 1.2.3.4 + # searches: + # - ns1.svc.cluster-domain.example + # - my.dns.search.suffix + # options: + # - name: ndots + # value: "2" + # - name: edns0 + securityContext: + fsGroup: 65534 + runAsGroup: 65534 + runAsNonRoot: true + runAsUser: 65534 + seccompProfile: + type: RuntimeDefault + + ## Container-specific security context configuration + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + containerSecurityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + + ## If false then the user will opt out of automounting API credentials. + ## + automountServiceAccountToken: true + + patch: + enabled: true + image: + repository: rancher/mirrored-ingress-nginx-kube-webhook-certgen + tag: v1.4.3 + sha: "" + pullPolicy: IfNotPresent + resources: {} + ## Provide a priority class name to the webhook patching job + ## + priorityClassName: "" + ttlSecondsAfterFinished: 60 + annotations: {} + # argocd.argoproj.io/hook: PreSync + # argocd.argoproj.io/hook-delete-policy: HookSucceeded + podAnnotations: {} + nodeSelector: {} + affinity: {} + tolerations: [] + + ## SecurityContext holds pod-level security attributes and common container settings. + ## This defaults to non root user with uid 2000 and gid 2000. *v1.PodSecurityContext false + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 2000 + seccompProfile: + type: RuntimeDefault + ## Service account for Prometheus Operator Webhook Job Patch to use. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + create: true + automountServiceAccountToken: true + + # Security context for create job container + createSecretJob: + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + + # Security context for patch job container + patchWebhookJob: + securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + + # Use certmanager to generate webhook certs + certManager: + enabled: false + # self-signed root certificate + rootCert: + duration: "" # default to be 5y + admissionCert: + duration: "" # default to be 1y + # issuerRef: + # name: "issuer" + # kind: "ClusterIssuer" + + ## Namespaces to scope the interaction of the Prometheus Operator and the apiserver (allow list). + ## This is mutually exclusive with denyNamespaces. Setting this to an empty object will disable the configuration + ## + namespaces: {} + # releaseNamespace: true + # additional: + # - kube-system + + ## Namespaces not to scope the interaction of the Prometheus Operator (deny list). + ## + denyNamespaces: [] + + ## Filter namespaces to look for prometheus-operator custom resources + ## + alertmanagerInstanceNamespaces: [] + alertmanagerConfigNamespaces: [] + prometheusInstanceNamespaces: [] + thanosRulerInstanceNamespaces: [] + + ## The clusterDomain value will be added to the cluster.peer option of the alertmanager. + ## Without this specified option cluster.peer will have value alertmanager-monitoring-alertmanager-0.alertmanager-operated:9094 (default value) + ## With this specified option cluster.peer will have value alertmanager-monitoring-alertmanager-0.alertmanager-operated.namespace.svc.cluster-domain:9094 + ## + # clusterDomain: "cluster.local" + + networkPolicy: + ## Enable creation of NetworkPolicy resources. + ## + enabled: false + + ## Flavor of the network policy to use. + # Can be: + # * kubernetes for networking.k8s.io/v1/NetworkPolicy + # * cilium for cilium.io/v2/CiliumNetworkPolicy + flavor: kubernetes + + # cilium: + # egress: + + ## match labels used in selector + # matchLabels: {} + + ## Service account for Prometheus Operator to use. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + create: true + name: "" + automountServiceAccountToken: true + + ## Configuration for Prometheus operator service + ## + service: + annotations: {} + labels: {} + clusterIP: "" + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30080 + + nodePortTls: 30443 + + ## Additional ports to open for Prometheus operator service + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services + ## + additionalPorts: [] + + ## Loadbalancer IP + ## Only use if service.type is "LoadBalancer" + ## + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## NodePort, ClusterIP, LoadBalancer + ## + type: ClusterIP + + ## List of IP addresses at which the Prometheus server service is available + ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips + ## + externalIPs: [] + + # ## Labels to add to the operator deployment + # ## + labels: {} + + ## Annotations to add to the operator deployment + ## + annotations: {} + + ## Labels to add to the operator pod + ## + podLabels: {} + + ## Annotations to add to the operator pod + ## + podAnnotations: {} + + ## Assign a PriorityClassName to pods if set + # priorityClassName: "" + + ## Define Log Format + # Use logfmt (default) or json logging + # logFormat: logfmt + + ## Decrease log verbosity to errors only + # logLevel: error + + kubeletService: + ## If true, the operator will create and maintain a service for scraping kubelets + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/helm/prometheus-operator/README.md + ## + enabled: true + namespace: kube-system + selector: "" + ## Use '{{ template "kube-prometheus-stack.fullname" . }}-kubelet' by default + name: "" + + ## Create a servicemonitor for the operator + ## + serviceMonitor: + ## If true, create a serviceMonitor for prometheus operator + ## + selfMonitor: true + + ## Labels for ServiceMonitor + additionalLabels: {} + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## Scrape timeout. If not set, the Prometheus default scrape timeout is used. + scrapeTimeout: "" + + ## Metric relabel configs to apply to samples before ingestion. + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + # relabel configs to apply to samples before ingestion. + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Resource limits & requests + ## + resources: {} + # limits: + # cpu: 200m + # memory: 200Mi + # requests: + # cpu: 100m + # memory: 100Mi + + ## Operator Environment + ## env: + ## VARIABLE: value + env: + GOGC: "30" + + # Required for use in managed kubernetes clusters (such as AWS EKS) with custom CNI (such as calico), + # because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working + ## + hostNetwork: false + + ## Define which Nodes the Pods are scheduled on. + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Tolerations for use with node taints + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + # - key: "key" + # operator: "Equal" + # value: "value" + # effect: "NoSchedule" + + ## Assign custom affinity rules to the prometheus operator + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + affinity: {} + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/e2e-az-name + # operator: In + # values: + # - e2e-az1 + # - e2e-az2 + dnsConfig: {} + # nameservers: + # - 1.2.3.4 + # searches: + # - ns1.svc.cluster-domain.example + # - my.dns.search.suffix + # options: + # - name: ndots + # value: "2" + # - name: edns0 + securityContext: + fsGroup: 65534 + runAsGroup: 65534 + runAsNonRoot: true + runAsUser: 65534 + seccompProfile: + type: RuntimeDefault + + ## Container-specific security context configuration + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + ## + containerSecurityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + + # Enable vertical pod autoscaler support for prometheus-operator + verticalPodAutoscaler: + enabled: false + + # Recommender responsible for generating recommendation for the object. + # List should be empty (then the default recommender will generate the recommendation) + # or contain exactly one recommender. + # recommenders: + # - name: custom-recommender-performance + + # List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory + controlledResources: [] + # Specifies which resource values should be controlled: RequestsOnly or RequestsAndLimits. + # controlledValues: RequestsAndLimits + + # Define the max allowed resources for the pod + maxAllowed: {} + # cpu: 200m + # memory: 100Mi + # Define the min allowed resources for the pod + minAllowed: {} + # cpu: 200m + # memory: 100Mi + + updatePolicy: + # Specifies minimal number of replicas which need to be alive for VPA Updater to attempt pod eviction + # minReplicas: 1 + # Specifies whether recommended updates are applied when a Pod is started and whether recommended updates + # are applied during the life of a Pod. Possible values are "Off", "Initial", "Recreate", and "Auto". + updateMode: Auto + + ## Prometheus-operator image + ## + image: + repository: rancher/mirrored-prometheus-operator-prometheus-operator + tag: v0.75.1 + sha: "" + pullPolicy: IfNotPresent + + ## Prometheus image to use for prometheuses managed by the operator + ## + # prometheusDefaultBaseImage: prometheus/prometheus + + ## Prometheus image registry to use for prometheuses managed by the operator + ## + # prometheusDefaultBaseImageRegistry: quay.io + + ## Alertmanager image to use for alertmanagers managed by the operator + ## + # alertmanagerDefaultBaseImage: prometheus/alertmanager + + ## Alertmanager image registry to use for alertmanagers managed by the operator + ## + # alertmanagerDefaultBaseImageRegistry: quay.io + + ## Prometheus-config-reloader + ## + prometheusConfigReloader: + image: + repository: rancher/mirrored-prometheus-operator-prometheus-config-reloader + tag: v0.75.1 + sha: "" + + # add prometheus config reloader liveness and readiness probe. Default: false + enableProbe: false + + # resource config for prometheusConfigReloader + resources: {} + # requests: + # cpu: 200m + # memory: 50Mi + # limits: + # cpu: 200m + # memory: 50Mi + + ## Thanos side-car image when configured + ## + thanosImage: + repository: rancher/mirrored-thanos-thanos + tag: v0.35.1 + sha: "" + + ## Set a Label Selector to filter watched prometheus and prometheusAgent + ## + prometheusInstanceSelector: "" + + ## Set a Label Selector to filter watched alertmanager + ## + alertmanagerInstanceSelector: "" + + ## Set a Label Selector to filter watched thanosRuler + thanosRulerInstanceSelector: "" + + ## Set a Field Selector to filter watched secrets + ## + secretFieldSelector: "type!=kubernetes.io/dockercfg,type!=kubernetes.io/service-account-token,type!=helm.sh/release.v1" + + ## If false then the user will opt out of automounting API credentials. + ## + automountServiceAccountToken: true + + ## Additional volumes + ## + extraVolumes: [] + + ## Additional volume mounts + ## + extraVolumeMounts: [] + +## Deploy a Prometheus instance +## +prometheus: + enabled: true + + ## Toggle prometheus into agent mode + ## Note many of features described below (e.g. rules, query, alerting, remote read, thanos) will not work in agent mode. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/designs/prometheus-agent.md + ## + agentMode: false + + ## Annotations for Prometheus + ## + annotations: {} + + ## Configure network policy for the prometheus + networkPolicy: + enabled: false + + ## Flavor of the network policy to use. + # Can be: + # * kubernetes for networking.k8s.io/v1/NetworkPolicy + # * cilium for cilium.io/v2/CiliumNetworkPolicy + flavor: kubernetes + + # cilium: + # endpointSelector: + # egress: + # ingress: + + # egress: + # - {} + # ingress: + # - {} + # podSelector: + # matchLabels: + # app: prometheus + + ## Service account for Prometheuses to use. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ + ## + serviceAccount: + create: true + name: "" + annotations: {} + automountServiceAccountToken: true + + # Service for thanos service discovery on sidecar + # Enable this can make Thanos Query can use + # `--store=dnssrv+_grpc._tcp.${kube-prometheus-stack.fullname}-thanos-discovery.${namespace}.svc.cluster.local` to discovery + # Thanos sidecar on prometheus nodes + # (Please remember to change ${kube-prometheus-stack.fullname} and ${namespace}. Not just copy and paste!) + thanosService: + enabled: false + annotations: {} + labels: {} + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: ClusterIP + + ## Service dual stack + ## + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + + ## gRPC port config + portName: grpc + port: 10901 + targetPort: "grpc" + + ## HTTP port config (for metrics) + httpPortName: http + httpPort: 10902 + targetHttpPort: "http" + + ## ClusterIP to assign + # Default is to make this a headless service ("None") + clusterIP: "None" + + ## Port to expose on each node, if service type is NodePort + ## + nodePort: 30901 + httpNodePort: 30902 + + # ServiceMonitor to scrape Sidecar metrics + # Needs thanosService to be enabled as well + thanosServiceMonitor: + enabled: false + interval: "" + + ## Additional labels + ## + additionalLabels: {} + + ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS. + scheme: "" + + ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS. + ## Of type: https://github.com/coreos/prometheus-operator/blob/main/Documentation/api.md#tlsconfig + tlsConfig: {} + + bearerTokenFile: + + ## Metric relabel configs to apply to samples before ingestion. + metricRelabelings: [] + + ## relabel configs to apply to samples before ingestion. + relabelings: [] + + # Service for external access to sidecar + # Enabling this creates a service to expose thanos-sidecar outside the cluster. + thanosServiceExternal: + enabled: false + annotations: {} + labels: {} + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## gRPC port config + portName: grpc + port: 10901 + targetPort: "grpc" + + ## HTTP port config (for metrics) + httpPortName: http + httpPort: 10902 + targetHttpPort: "http" + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: LoadBalancer + + ## Port to expose on each node + ## + nodePort: 30901 + httpNodePort: 30902 + + ## Configuration for Prometheus service + ## + service: + annotations: {} + labels: {} + clusterIP: "" + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + + ## Port for Prometheus Service to listen on + ## + port: 9090 + + ## To be used with a proxy extraContainer port + targetPort: 8081 + + ## Port for Prometheus Reloader to listen on + ## + reloaderWebPort: 8080 + + ## List of IP addresses at which the Prometheus server service is available + ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips + ## + externalIPs: [] + + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30090 + + ## Loadbalancer IP + ## Only use if service.type is "LoadBalancer" + loadBalancerIP: "" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: ClusterIP + + ## Additional ports to open for Prometheus service + ## + additionalPorts: [] + # additionalPorts: + # - name: oauth-proxy + # port: 8081 + # targetPort: 8081 + # - name: oauth-metrics + # port: 8082 + # targetPort: 8082 + + ## Consider that all endpoints are considered "ready" even if the Pods themselves are not + ## Ref: https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#ServiceSpec + publishNotReadyAddresses: false + + ## If you want to make sure that connections from a particular client are passed to the same Pod each time + ## Accepts 'ClientIP' or 'None' + ## + sessionAffinity: None + + ## If you want to modify the ClientIP sessionAffinity timeout + ## The value must be >0 && <=86400(for 1 day) if ServiceAffinity == "ClientIP" + ## + sessionAffinityConfig: + clientIP: + timeoutSeconds: 10800 + + ## Configuration for creating a separate Service for each statefulset Prometheus replica + ## + servicePerReplica: + enabled: false + annotations: {} + + ## Port for Prometheus Service per replica to listen on + ## + port: 9090 + + ## To be used with a proxy extraContainer port + targetPort: 9090 + + ## Port to expose on each node + ## Only used if servicePerReplica.type is 'NodePort' + ## + nodePort: 30091 + + ## Loadbalancer source IP ranges + ## Only used if servicePerReplica.type is "LoadBalancer" + loadBalancerSourceRanges: [] + + ## Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints + ## + externalTrafficPolicy: Cluster + + ## Service type + ## + type: ClusterIP + + ## Service dual stack + ## + ipDualStack: + enabled: false + ipFamilies: ["IPv6", "IPv4"] + ipFamilyPolicy: "PreferDualStack" + + ## Configure pod disruption budgets for Prometheus + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/#specifying-a-poddisruptionbudget + ## + podDisruptionBudget: + enabled: false + minAvailable: 1 + maxUnavailable: "" + + # Ingress exposes thanos sidecar outside the cluster + thanosIngress: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + labels: {} + servicePort: 10901 + + ## Port to expose on each node + ## Only used if service.type is 'NodePort' + ## + nodePort: 30901 + + ## Hosts must be provided if Ingress is enabled. + ## + hosts: [] + # - thanos-gateway.domain.com + + ## Paths to use for ingress rules + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## TLS configuration for Thanos Ingress + ## Secret must be manually created in the namespace + ## + tls: [] + # - secretName: thanos-gateway-tls + # hosts: + # - thanos-gateway.domain.com + # + + ## ExtraSecret can be used to store various data in an extra secret + ## (use it for example to store hashed basic auth credentials) + extraSecret: + ## if not set, name will be auto generated + # name: "" + annotations: {} + data: {} + # auth: | + # foo:$apr1$OFG3Xybp$ckL0FHDAkoXYIlH9.cysT0 + # someoneelse:$apr1$DMZX2Z4q$6SbQIfyuLQd.xmo/P0m2c. + + ingress: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + labels: {} + + ## Redirect ingress to an additional defined port on the service + # servicePort: 8081 + + ## Hostnames. + ## Must be provided if Ingress is enabled. + ## + # hosts: + # - prometheus.domain.com + hosts: [] + + ## Paths to use for ingress rules - one path should match the prometheusSpec.routePrefix + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## TLS configuration for Prometheus Ingress + ## Secret must be manually created in the namespace + ## + tls: [] + # - secretName: prometheus-general-tls + # hosts: + # - prometheus.example.com + + ## Configuration for creating an Ingress that will map to each Prometheus replica service + ## prometheus.servicePerReplica must be enabled + ## + ingressPerReplica: + enabled: false + + # For Kubernetes >= 1.18 you should specify the ingress-controller via the field ingressClassName + # See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#specifying-the-class-of-an-ingress + # ingressClassName: nginx + + annotations: {} + labels: {} + + ## Final form of the hostname for each per replica ingress is + ## {{ ingressPerReplica.hostPrefix }}-{{ $replicaNumber }}.{{ ingressPerReplica.hostDomain }} + ## + ## Prefix for the per replica ingress that will have `-$replicaNumber` + ## appended to the end + hostPrefix: "" + ## Domain that will be used for the per replica ingress + hostDomain: "" + + ## Paths to use for ingress rules + ## + paths: [] + # - / + + ## For Kubernetes >= 1.18 you should specify the pathType (determines how Ingress paths should be matched) + ## See https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/#better-path-matching-with-path-types + # pathType: ImplementationSpecific + + ## Secret name containing the TLS certificate for Prometheus per replica ingress + ## Secret must be manually created in the namespace + tlsSecretName: "" + + ## Separated secret for each per replica Ingress. Can be used together with cert-manager + ## + tlsSecretPerReplica: + enabled: false + ## Final form of the secret for each per replica ingress is + ## {{ tlsSecretPerReplica.prefix }}-{{ $replicaNumber }} + ## + prefix: "prometheus" + + ## Configure additional options for default pod security policy for Prometheus + ## ref: https://kubernetes.io/docs/concepts/policy/pod-security-policy/ + podSecurityPolicy: + allowedCapabilities: [] + allowedHostPaths: [] + volumes: [] + + serviceMonitor: + ## If true, create a serviceMonitor for prometheus + ## + selfMonitor: true + + ## Scrape interval. If not set, the Prometheus default scrape interval is used. + ## + interval: "" + + ## Additional labels + ## + additionalLabels: {} + + ## SampleLimit defines per-scrape limit on number of scraped samples that will be accepted. + ## + sampleLimit: 0 + + ## TargetLimit defines a limit on the number of scraped targets that will be accepted. + ## + targetLimit: 0 + + ## Per-scrape limit on number of labels that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelLimit: 0 + + ## Per-scrape limit on length of labels name that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelNameLengthLimit: 0 + + ## Per-scrape limit on length of labels value that will be accepted for a sample. Only valid in Prometheus versions 2.27.0 and newer. + ## + labelValueLengthLimit: 0 + + ## scheme: HTTP scheme to use for scraping. Can be used with `tlsConfig` for example if using istio mTLS. + scheme: "" + + ## tlsConfig: TLS configuration to use when scraping the endpoint. For example if using istio mTLS. + ## Of type: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#tlsconfig + tlsConfig: {} + + bearerTokenFile: + + ## Metric relabel configs to apply to samples before ingestion. + ## + metricRelabelings: [] + # - action: keep + # regex: 'kube_(daemonset|deployment|pod|namespace|node|statefulset).+' + # sourceLabels: [__name__] + + # relabel configs to apply to samples before ingestion. + ## + relabelings: [] + # - sourceLabels: [__meta_kubernetes_pod_node_name] + # separator: ; + # regex: ^(.*)$ + # targetLabel: nodename + # replacement: $1 + # action: replace + + ## Additional Endpoints + ## + additionalEndpoints: [] + # - port: oauth-metrics + # path: /metrics + + ## Settings affecting prometheusSpec + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#prometheusspec + ## + prometheusSpec: + ## Statefulset's persistent volume claim retention policy + ## pvcDeleteOnStsDelete and pvcDeleteOnStsScale determine whether + ## statefulset's PVCs are deleted (true) or retained (false) on scaling down + ## and deleting statefulset, respectively. Requires 1.27.0+. + ## Ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#persistentvolumeclaim-retention + persistentVolumeClaimRetentionPolicy: {} + # whenDeleted: Retain + # whenScaled: Retain + + ## If true, pass --storage.tsdb.max-block-duration=2h to prometheus. This is already done if using Thanos + ## + ## AutomountServiceAccountToken indicates whether a service account token should be automatically mounted in the pod, + ## If the field isn’t set, the operator mounts the service account token by default. + ## Warning: be aware that by default, Prometheus requires the service account token for Kubernetes service discovery, + ## It is possible to use strategic merge patch to project the service account token into the ‘prometheus’ container. + automountServiceAccountToken: true + + disableCompaction: false + ## APIServerConfig + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#apiserverconfig + ## + apiserverConfig: {} + + ## Allows setting additional arguments for the Prometheus container + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.Prometheus + additionalArgs: [] + + ## Interval between consecutive scrapes. + ## Defaults to 30s. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/release-0.44/pkg/prometheus/promcfg.go#L180-L183 + ## + scrapeInterval: "30s" + + ## Number of seconds to wait for target to respond before erroring + ## + # scrapeTimeout: "" + + ## List of scrape classes to expose to scraping objects such as + ## PodMonitors, ServiceMonitors, Probes and ScrapeConfigs. + ## + scrapeClasses: [] + # - name: istio-mtls + # default: false + # tlsConfig: + # caFile: /etc/prometheus/secrets/istio.default/root-cert.pem + # certFile: /etc/prometheus/secrets/istio.default/cert-chain.pem + + ## Interval between consecutive evaluations. + ## + evaluationInterval: "30s" + + ## ListenLocal makes the Prometheus server listen on loopback, so that it does not bind against the Pod IP. + ## + listenLocal: false + + ## EnableAdminAPI enables Prometheus the administrative HTTP API which includes functionality such as deleting time series. + ## This is disabled by default. + ## ref: https://prometheus.io/docs/prometheus/latest/querying/api/#tsdb-admin-apis + ## + enableAdminAPI: false + + ## Sets version of Prometheus overriding the Prometheus version as derived + ## from the image tag. Useful in cases where the tag does not follow semver v2. + version: "" + + ## WebTLSConfig defines the TLS parameters for HTTPS + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#webtlsconfig + web: {} + + ## Exemplars related settings that are runtime reloadable. + ## It requires to enable the exemplar storage feature to be effective. + exemplars: "" + ## Maximum number of exemplars stored in memory for all series. + ## If not set, Prometheus uses its default value. + ## A value of zero or less than zero disables the storage. + # maxSize: 100000 + + # EnableFeatures API enables access to Prometheus disabled features. + # ref: https://prometheus.io/docs/prometheus/latest/disabled_features/ + enableFeatures: [] + # - exemplar-storage + + ## Image of Prometheus. + ## + image: + repository: rancher/mirrored-prometheus-prometheus + tag: v2.53.1 + sha: "" + + ## Tolerations for use with node taints + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + # - key: "key" + # operator: "Equal" + # value: "value" + # effect: "NoSchedule" + + ## If specified, the pod's topology spread constraints. + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/ + ## + topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app: prometheus + + ## Alertmanagers to which alerts will be sent + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#alertmanagerendpoints + ## + ## Default configuration will connect to the alertmanager deployed as part of this release + ## + alertingEndpoints: [] + # - name: "" + # namespace: "" + # port: http + # scheme: http + # pathPrefix: "" + # tlsConfig: {} + # bearerTokenFile: "" + # apiVersion: v2 + + ## External labels to add to any time series or alerts when communicating with external systems + ## + externalLabels: {} + + ## enable --web.enable-remote-write-receiver flag on prometheus-server + ## + enableRemoteWriteReceiver: false + + ## Name of the external label used to denote replica name + ## + replicaExternalLabelName: "" + + ## If true, the Operator won't add the external label used to denote replica name + ## + replicaExternalLabelNameClear: false + + ## Name of the external label used to denote Prometheus instance name + ## + prometheusExternalLabelName: "" + + ## If true, the Operator won't add the external label used to denote Prometheus instance name + ## + prometheusExternalLabelNameClear: false + + ## External URL at which Prometheus will be reachable. + ## + externalUrl: "" + + ## Define which Nodes the Pods are scheduled on. + ## ref: https://kubernetes.io/docs/user-guide/node-selection/ + ## + nodeSelector: {} + + ## Secrets is a list of Secrets in the same namespace as the Prometheus object, which shall be mounted into the Prometheus Pods. + ## The Secrets are mounted into /etc/prometheus/secrets/. Secrets changes after initial creation of a Prometheus object are not + ## reflected in the running Pods. To change the secrets mounted into the Prometheus Pods, the object must be deleted and recreated + ## with the new list of secrets. + ## + secrets: [] + + ## ConfigMaps is a list of ConfigMaps in the same namespace as the Prometheus object, which shall be mounted into the Prometheus Pods. + ## The ConfigMaps are mounted into /etc/prometheus/configmaps/. + ## + configMaps: [] + + ## QuerySpec defines the query command line flags when starting Prometheus. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#queryspec + ## + query: {} + + ## If nil, select own namespace. Namespaces to be selected for PrometheusRules discovery. + ruleNamespaceSelector: {} + ## Example which selects PrometheusRules in namespaces with label "prometheus" set to "somelabel" + # ruleNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## If true, a nil or {} value for prometheus.prometheusSpec.ruleSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the PrometheusRule resources created + ## + ruleSelectorNilUsesHelmValues: false + + ## PrometheusRules to be selected for target discovery. + ## If {}, select all PrometheusRules + ## + ruleSelector: {} + ## Example which select all PrometheusRules resources + ## with label "prometheus" with values any of "example-rules" or "example-rules-2" + # ruleSelector: + # matchExpressions: + # - key: prometheus + # operator: In + # values: + # - example-rules + # - example-rules-2 + # + ## Example which select all PrometheusRules resources with label "role" set to "example-rules" + # ruleSelector: + # matchLabels: + # role: example-rules + + ## If true, a nil or {} value for prometheus.prometheusSpec.serviceMonitorSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the servicemonitors created + ## + serviceMonitorSelectorNilUsesHelmValues: false + + ## ServiceMonitors to be selected for target discovery. + ## If {}, select all ServiceMonitors + ## + serviceMonitorSelector: {} + ## Example which selects ServiceMonitors with label "prometheus" set to "somelabel" + # serviceMonitorSelector: + # matchLabels: + # prometheus: somelabel + + ## Namespaces to be selected for ServiceMonitor discovery. + ## + serviceMonitorNamespaceSelector: {} + ## Example which selects ServiceMonitors in namespaces with label "prometheus" set to "somelabel" + # serviceMonitorNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## If true, a nil or {} value for prometheus.prometheusSpec.podMonitorSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the podmonitors created + ## + podMonitorSelectorNilUsesHelmValues: false + + ## PodMonitors to be selected for target discovery. + ## If {}, select all PodMonitors + ## + podMonitorSelector: {} + ## Example which selects PodMonitors with label "prometheus" set to "somelabel" + # podMonitorSelector: + # matchLabels: + # prometheus: somelabel + + ## If nil, select own namespace. Namespaces to be selected for PodMonitor discovery. + podMonitorNamespaceSelector: {} + ## Example which selects PodMonitor in namespaces with label "prometheus" set to "somelabel" + # podMonitorNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## If true, a nil or {} value for prometheus.prometheusSpec.probeSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the probes created + ## + probeSelectorNilUsesHelmValues: true + + ## Probes to be selected for target discovery. + ## If {}, select all Probes + ## + probeSelector: {} + ## Example which selects Probes with label "prometheus" set to "somelabel" + # probeSelector: + # matchLabels: + # prometheus: somelabel + + ## If nil, select own namespace. Namespaces to be selected for Probe discovery. + probeNamespaceSelector: {} + ## Example which selects Probe in namespaces with label "prometheus" set to "somelabel" + # probeNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## If true, a nil or {} value for prometheus.prometheusSpec.scrapeConfigSelector will cause the + ## prometheus resource to be created with selectors based on values in the helm deployment, + ## which will also match the scrapeConfigs created + ## + scrapeConfigSelectorNilUsesHelmValues: true + + ## scrapeConfigs to be selected for target discovery. + ## If {}, select all scrapeConfigs + ## + scrapeConfigSelector: {} + ## Example which selects scrapeConfigs with label "prometheus" set to "somelabel" + # scrapeConfigSelector: + # matchLabels: + # prometheus: somelabel + + ## If nil, select own namespace. Namespaces to be selected for scrapeConfig discovery. + scrapeConfigNamespaceSelector: {} + ## Example which selects scrapeConfig in namespaces with label "prometheus" set to "somelabel" + # scrapeConfigNamespaceSelector: + # matchLabels: + # prometheus: somelabel + + ## How long to retain metrics + ## + retention: 10d + + ## Maximum size of metrics + ## + retentionSize: "" + + ## Allow out-of-order/out-of-bounds samples ingested into Prometheus for a specified duration + ## See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#tsdb + tsdb: + outOfOrderTimeWindow: 0s + + ## Enable compression of the write-ahead log using Snappy. + ## + walCompression: true + + ## If true, the Operator won't process any Prometheus configuration changes + ## + paused: false + + ## Number of replicas of each shard to deploy for a Prometheus deployment. + ## Number of replicas multiplied by shards is the total number of Pods created. + ## + replicas: 1 + + ## EXPERIMENTAL: Number of shards to distribute targets onto. + ## Number of replicas multiplied by shards is the total number of Pods created. + ## Note that scaling down shards will not reshard data onto remaining instances, it must be manually moved. + ## Increasing shards will not reshard data either but it will continue to be available from the same instances. + ## To query globally use Thanos sidecar and Thanos querier or remote write data to a central location. + ## Sharding is done on the content of the `__address__` target meta-label. + ## + shards: 1 + + ## Log level for Prometheus be configured in + ## + logLevel: info + + ## Log format for Prometheus be configured in + ## + logFormat: logfmt + + ## Prefix used to register routes, overriding externalUrl route. + ## Useful for proxies that rewrite URLs. + ## + routePrefix: / + + ## Standard object's metadata. More info: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#metadata + ## Metadata Labels and Annotations gets propagated to the prometheus pods. + ## + podMetadata: {} + # labels: + # app: prometheus + # k8s-app: prometheus + + ## Pod anti-affinity can prevent the scheduler from placing Prometheus replicas on the same node. + ## The default value "soft" means that the scheduler should *prefer* to not schedule two replica pods onto the same node but no guarantee is provided. + ## The value "hard" means that the scheduler is *required* to not schedule two replica pods onto the same node. + ## The value "" will disable pod anti-affinity so that no anti-affinity rules will be configured. + podAntiAffinity: "" + + ## If anti-affinity is enabled sets the topologyKey to use for anti-affinity. + ## This can be changed to, for example, failure-domain.beta.kubernetes.io/zone + ## + podAntiAffinityTopologyKey: kubernetes.io/hostname + + ## Assign custom affinity rules to the prometheus instance + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + ## + affinity: {} + # nodeAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # nodeSelectorTerms: + # - matchExpressions: + # - key: kubernetes.io/e2e-az-name + # operator: In + # values: + # - e2e-az1 + # - e2e-az2 + + ## The remote_read spec configuration for Prometheus. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#remotereadspec + remoteRead: [] + # - url: http://remote1/read + ## additionalRemoteRead is appended to remoteRead + additionalRemoteRead: [] + + ## The remote_write spec configuration for Prometheus. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#remotewritespec + remoteWrite: [] + # - url: http://remote1/push + ## additionalRemoteWrite is appended to remoteWrite + additionalRemoteWrite: [] + + ## Enable/Disable Grafana dashboards provisioning for prometheus remote write feature + remoteWriteDashboards: false + + ## Resource limits & requests + ## + resources: + limits: + memory: 3000Mi + cpu: 1000m + requests: + memory: 750Mi + cpu: 750m + + ## Prometheus StorageSpec for persistent data + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/storage.md + ## + storageSpec: {} + ## Using PersistentVolumeClaim + ## + # volumeClaimTemplate: + # spec: + # storageClassName: gluster + # accessModes: ["ReadWriteOnce"] + # resources: + # requests: + # storage: 50Gi + # selector: {} + + ## Using tmpfs volume + ## + # emptyDir: + # medium: Memory + + # Additional volumes on the output StatefulSet definition. + volumes: + - name: nginx-home + emptyDir: {} + - name: prometheus-nginx + configMap: + name: prometheus-nginx-proxy-config + defaultMode: 438 + + # Additional VolumeMounts on the output StatefulSet definition. + volumeMounts: [] + + ## AdditionalScrapeConfigs allows specifying additional Prometheus scrape configurations. Scrape configurations + ## are appended to the configurations generated by the Prometheus Operator. Job configurations must have the form + ## as specified in the official Prometheus documentation: + ## https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config. As scrape configs are + ## appended, the user is responsible to make sure it is valid. Note that using this feature may expose the possibility + ## to break upgrades of Prometheus. It is advised to review Prometheus release notes to ensure that no incompatible + ## scrape configs are going to break Prometheus after the upgrade. + ## AdditionalScrapeConfigs can be defined as a list or as a templated string. + ## + ## The scrape configuration example below will find master nodes, provided they have the name .*mst.*, relabel the + ## port to 2379 and allow etcd scraping provided it is running on all Kubernetes master nodes + ## + additionalScrapeConfigs: [] + # - job_name: kube-etcd + # kubernetes_sd_configs: + # - role: node + # scheme: https + # tls_config: + # ca_file: /etc/prometheus/secrets/etcd-client-cert/etcd-ca + # cert_file: /etc/prometheus/secrets/etcd-client-cert/etcd-client + # key_file: /etc/prometheus/secrets/etcd-client-cert/etcd-client-key + # relabel_configs: + # - action: labelmap + # regex: __meta_kubernetes_node_label_(.+) + # - source_labels: [__address__] + # action: replace + # targetLabel: __address__ + # regex: ([^:;]+):(\d+) + # replacement: ${1}:2379 + # - source_labels: [__meta_kubernetes_node_name] + # action: keep + # regex: .*mst.* + # - source_labels: [__meta_kubernetes_node_name] + # action: replace + # targetLabel: node + # regex: (.*) + # replacement: ${1} + # metric_relabel_configs: + # - regex: (kubernetes_io_hostname|failure_domain_beta_kubernetes_io_region|beta_kubernetes_io_os|beta_kubernetes_io_arch|beta_kubernetes_io_instance_type|failure_domain_beta_kubernetes_io_zone) + # action: labeldrop + # + ## If scrape config contains a repetitive section, you may want to use a template. + ## In the following example, you can see how to define `gce_sd_configs` for multiple zones + # additionalScrapeConfigs: | + # - job_name: "node-exporter" + # gce_sd_configs: + # {{range $zone := .Values.gcp_zones}} + # - project: "project1" + # zone: "{{$zone}}" + # port: 9100 + # {{end}} + # relabel_configs: + # ... + + + ## If additional scrape configurations are already deployed in a single secret file you can use this section. + ## Expected values are the secret name and key + ## Cannot be used with additionalScrapeConfigs + additionalScrapeConfigsSecret: {} + # enabled: false + # name: + # key: + + ## additionalPrometheusSecretsAnnotations allows to add annotations to the kubernetes secret. This can be useful + ## when deploying via spinnaker to disable versioning on the secret, strategy.spinnaker.io/versioned: 'false' + additionalPrometheusSecretsAnnotations: {} + + ## AdditionalAlertManagerConfigs allows for manual configuration of alertmanager jobs in the form as specified + ## in the official Prometheus documentation https://prometheus.io/docs/prometheus/latest/configuration/configuration/#. + ## AlertManager configurations specified are appended to the configurations generated by the Prometheus Operator. + ## As AlertManager configs are appended, the user is responsible to make sure it is valid. Note that using this + ## feature may expose the possibility to break upgrades of Prometheus. It is advised to review Prometheus release + ## notes to ensure that no incompatible AlertManager configs are going to break Prometheus after the upgrade. + ## + additionalAlertManagerConfigs: [] + # - consul_sd_configs: + # - server: consul.dev.test:8500 + # scheme: http + # datacenter: dev + # tag_separator: ',' + # services: + # - metrics-prometheus-alertmanager + + ## If additional alertmanager configurations are already deployed in a single secret, or you want to manage + ## them separately from the helm deployment, you can use this section. + ## Expected values are the secret name and key + ## Cannot be used with additionalAlertManagerConfigs + additionalAlertManagerConfigsSecret: {} + # name: + # key: + # optional: false + + ## AdditionalAlertRelabelConfigs allows specifying Prometheus alert relabel configurations. Alert relabel configurations specified are appended + ## to the configurations generated by the Prometheus Operator. Alert relabel configurations specified must have the form as specified in the + ## official Prometheus documentation: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#alert_relabel_configs. + ## As alert relabel configs are appended, the user is responsible to make sure it is valid. Note that using this feature may expose the + ## possibility to break upgrades of Prometheus. It is advised to review Prometheus release notes to ensure that no incompatible alert relabel + ## configs are going to break Prometheus after the upgrade. + ## + additionalAlertRelabelConfigs: [] + # - separator: ; + # regex: prometheus_replica + # replacement: $1 + # action: labeldrop + + ## If additional alert relabel configurations are already deployed in a single secret, or you want to manage + ## them separately from the helm deployment, you can use this section. + ## Expected values are the secret name and key + ## Cannot be used with additionalAlertRelabelConfigs + additionalAlertRelabelConfigsSecret: {} + # name: + # key: + + ## SecurityContext holds pod-level security attributes and common container settings. + ## This defaults to non root user with uid 1000 and gid 2000. + ## https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md + ## + securityContext: + runAsGroup: 2000 + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 2000 + seccompProfile: + type: RuntimeDefault + + ## Priority class assigned to the Pods + ## + priorityClassName: "" + + ## Thanos configuration allows configuring various aspects of a Prometheus server in a Thanos environment. + ## This section is experimental, it may change significantly without deprecation notice in any release. + ## This is experimental and may change significantly without backward compatibility in any release. + ## ref: https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#thanosspec + ## + thanos: {} + # secretProviderClass: + # provider: gcp + # parameters: + # secrets: | + # - resourceName: "projects/$PROJECT_ID/secrets/testsecret/versions/latest" + # fileName: "objstore.yaml" + ## ObjectStorageConfig configures object storage in Thanos. + # objectStorageConfig: + # # use existing secret, if configured, objectStorageConfig.secret will not be used + # existingSecret: {} + # # name: "" + # # key: "" + # # will render objectStorageConfig secret data and configure it to be used by Thanos custom resource, + # # ignored when prometheusspec.thanos.objectStorageConfig.existingSecret is set + # # https://thanos.io/tip/thanos/storage.md/#s3 + # secret: {} + # # type: S3 + # # config: + # # bucket: "" + # # endpoint: "" + # # region: "" + # # access_key: "" + # # secret_key: "" + + proxy: + image: + repository: rancher/mirrored-library-nginx + tag: 1.24.0-alpine + + ## Containers allows injecting additional containers. This is meant to allow adding an authentication proxy to a Prometheus pod. + ## if using proxy extraContainer update targetPort with proxy container port + containers: | + - name: prometheus-proxy + args: + - nginx + - -g + - daemon off; + - -c + - /nginx/nginx.conf + image: "{{ template "system_default_registry" . }}{{ .Values.prometheus.prometheusSpec.proxy.image.repository }}:{{ .Values.prometheus.prometheusSpec.proxy.image.tag }}" + ports: + - containerPort: 8081 + name: nginx-http + protocol: TCP + volumeMounts: + - mountPath: /nginx + name: prometheus-nginx + - mountPath: /var/cache/nginx + name: nginx-home + securityContext: + runAsUser: 101 + runAsGroup: 101 + + ## InitContainers allows injecting additional initContainers. This is meant to allow doing some changes + ## (permissions, dir tree) on mounted volumes before starting prometheus + initContainers: [] + + ## PortName to use for Prometheus. + ## + portName: "http-web" + + ## ArbitraryFSAccessThroughSMs configures whether configuration based on a service monitor can access arbitrary files + ## on the file system of the Prometheus container e.g. bearer token files. + arbitraryFSAccessThroughSMs: false + + ## OverrideHonorLabels if set to true overrides all user configured honor_labels. If HonorLabels is set in ServiceMonitor + ## or PodMonitor to true, this overrides honor_labels to false. + overrideHonorLabels: false + + ## OverrideHonorTimestamps allows to globally enforce honoring timestamps in all scrape configs. + overrideHonorTimestamps: false + + ## When ignoreNamespaceSelectors is set to true, namespaceSelector from all PodMonitor, ServiceMonitor and Probe objects will be ignored, + ## they will only discover targets within the namespace of the PodMonitor, ServiceMonitor and Probe object, + ## and servicemonitors will be installed in the default service namespace. + ## Defaults to false. + ignoreNamespaceSelectors: false + + ## EnforcedNamespaceLabel enforces adding a namespace label of origin for each alert and metric that is user created. + ## The label value will always be the namespace of the object that is being created. + ## Disabled by default + enforcedNamespaceLabel: "" + + ## PrometheusRulesExcludedFromEnforce - list of prometheus rules to be excluded from enforcing of adding namespace labels. + ## Works only if enforcedNamespaceLabel set to true. Make sure both ruleNamespace and ruleName are set for each pair + ## Deprecated, use `excludedFromEnforcement` instead + prometheusRulesExcludedFromEnforce: [] + + ## ExcludedFromEnforcement - list of object references to PodMonitor, ServiceMonitor, Probe and PrometheusRule objects + ## to be excluded from enforcing a namespace label of origin. + ## Works only if enforcedNamespaceLabel set to true. + ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#objectreference + excludedFromEnforcement: [] + + ## QueryLogFile specifies the file to which PromQL queries are logged. Note that this location must be writable, + ## and can be persisted using an attached volume. Alternatively, the location can be set to a stdout location such + ## as /dev/stdout to log querie information to the default Prometheus log stream. This is only available in versions + ## of Prometheus >= 2.16.0. For more details, see the Prometheus docs (https://prometheus.io/docs/guides/query-log/) + queryLogFile: false + + # Use to set global sample_limit for Prometheus. This act as default SampleLimit for ServiceMonitor or/and PodMonitor. + # Set to 'false' to disable global sample_limit. or set to a number to override the default value. + sampleLimit: false + + # EnforcedKeepDroppedTargetsLimit defines on the number of targets dropped by relabeling that will be kept in memory. + # The value overrides any spec.keepDroppedTargets set by ServiceMonitor, PodMonitor, Probe objects unless spec.keepDroppedTargets + # is greater than zero and less than spec.enforcedKeepDroppedTargets. 0 means no limit. + enforcedKeepDroppedTargets: 0 + + ## EnforcedSampleLimit defines global limit on number of scraped samples that will be accepted. This overrides any SampleLimit + ## set per ServiceMonitor or/and PodMonitor. It is meant to be used by admins to enforce the SampleLimit to keep overall + ## number of samples/series under the desired limit. Note that if SampleLimit is lower that value will be taken instead. + enforcedSampleLimit: false + + ## EnforcedTargetLimit defines a global limit on the number of scraped targets. This overrides any TargetLimit set + ## per ServiceMonitor or/and PodMonitor. It is meant to be used by admins to enforce the TargetLimit to keep the overall + ## number of targets under the desired limit. Note that if TargetLimit is lower, that value will be taken instead, except + ## if either value is zero, in which case the non-zero value will be used. If both values are zero, no limit is enforced. + enforcedTargetLimit: false + + + ## Per-scrape limit on number of labels that will be accepted for a sample. If more than this number of labels are present + ## post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus versions + ## 2.27.0 and newer. + enforcedLabelLimit: false + + ## Per-scrape limit on length of labels name that will be accepted for a sample. If a label name is longer than this number + ## post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus versions + ## 2.27.0 and newer. + enforcedLabelNameLengthLimit: false + + ## Per-scrape limit on length of labels value that will be accepted for a sample. If a label value is longer than this + ## number post metric-relabeling, the entire scrape will be treated as failed. 0 means no limit. Only valid in Prometheus + ## versions 2.27.0 and newer. + enforcedLabelValueLengthLimit: false + + ## AllowOverlappingBlocks enables vertical compaction and vertical query merge in Prometheus. This is still experimental + ## in Prometheus so it may change in any upcoming release. + allowOverlappingBlocks: false + + ## Minimum number of seconds for which a newly created pod should be ready without any of its container crashing for it to + ## be considered available. Defaults to 0 (pod will be considered available as soon as it is ready). + minReadySeconds: 0 + + # Required for use in managed kubernetes clusters (such as AWS EKS) with custom CNI (such as calico), + # because control-plane managed by AWS cannot communicate with pods' IP CIDR and admission webhooks are not working + # Use the host's network namespace if true. Make sure to understand the security implications if you want to enable it. + # When hostNetwork is enabled, this will set dnsPolicy to ClusterFirstWithHostNet automatically. + hostNetwork: false + + # HostAlias holds the mapping between IP and hostnames that will be injected + # as an entry in the pod’s hosts file. + hostAliases: [] + # - ip: 10.10.0.100 + # hostnames: + # - a1.app.local + # - b1.app.local + + ## TracingConfig configures tracing in Prometheus. + ## See https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#prometheustracingconfig + tracingConfig: {} + + ## Additional configuration which is not covered by the properties above. (passed through tpl) + additionalConfig: {} + + ## Additional configuration which is not covered by the properties above. + ## Useful, if you need advanced templating inside alertmanagerSpec. + ## Otherwise, use prometheus.prometheusSpec.additionalConfig (passed through tpl) + additionalConfigString: "" + + ## Defines the maximum time that the `prometheus` container's startup probe + ## will wait before being considered failed. The startup probe will return + ## success after the WAL replay is complete. If set, the value should be + ## greater than 60 (seconds). Otherwise it will be equal to 900 seconds (15 + ## minutes). + maximumStartupDurationSeconds: 0 + + additionalRulesForClusterRole: [] + # - apiGroups: [ "" ] + # resources: + # - nodes/proxy + # verbs: [ "get", "list", "watch" ] + + additionalServiceMonitors: [] + ## Name of the ServiceMonitor to create + ## + # - name: "" + + ## Additional labels to set used for the ServiceMonitorSelector. Together with standard labels from + ## the chart + ## + # additionalLabels: {} + + ## Service label for use in assembling a job name of the form

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